summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-05-23 22:11:10 +0000
committerAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-05-23 22:11:10 +0000
commitdbaaafa705ca548059aac958082776f219b2daef (patch)
treee6e62c393c7d7a9d42f10a0efc315995b73d3ca8
parentc0c2076f62b1c430c14737fbd3d8896a37bd2f6b (diff)
KeyNote version 2 trust-management system (security policy handling).
Utilities to follow.
-rw-r--r--lib/libkeynote/HOWTO.add.crypto71
-rw-r--r--lib/libkeynote/LICENSE21
-rw-r--r--lib/libkeynote/Makefile31
-rw-r--r--lib/libkeynote/Makefile.dist180
-rw-r--r--lib/libkeynote/Misc/getopt.c83
-rw-r--r--lib/libkeynote/Misc/getopt.h6
-rw-r--r--lib/libkeynote/Misc/keynote.btm14
-rw-r--r--lib/libkeynote/Misc/keynote.gifbin0 -> 128 bytes
-rw-r--r--lib/libkeynote/README97
-rw-r--r--lib/libkeynote/TODO14
-rw-r--r--lib/libkeynote/assertion.h106
-rw-r--r--lib/libkeynote/aux.c511
-rw-r--r--lib/libkeynote/base64.c348
-rw-r--r--lib/libkeynote/doc/keynote-spec1562
-rw-r--r--lib/libkeynote/environment.c874
-rw-r--r--lib/libkeynote/environment.h68
-rw-r--r--lib/libkeynote/keynote-keygen.c408
-rw-r--r--lib/libkeynote/keynote-sign.c250
-rw-r--r--lib/libkeynote/keynote-sigver.c137
-rw-r--r--lib/libkeynote/keynote-ver.l273
-rw-r--r--lib/libkeynote/keynote-ver.y70
-rw-r--r--lib/libkeynote/keynote-verify.c447
-rw-r--r--lib/libkeynote/keynote.h195
-rw-r--r--lib/libkeynote/keynote.l749
-rw-r--r--lib/libkeynote/keynote.y899
-rw-r--r--lib/libkeynote/man/keynote-keygen.1113
-rw-r--r--lib/libkeynote/man/keynote-sign.1129
-rw-r--r--lib/libkeynote/man/keynote-sigver.173
-rw-r--r--lib/libkeynote/man/keynote-verify.1138
-rw-r--r--lib/libkeynote/man/keynote.3770
-rw-r--r--lib/libkeynote/man/keynote.4266
-rw-r--r--lib/libkeynote/parse_assertion.c623
-rw-r--r--lib/libkeynote/signature.c1420
-rw-r--r--lib/libkeynote/signature.h64
-rw-r--r--lib/libkeynote/testsuite/auth11
-rw-r--r--lib/libkeynote/testsuite/auth21
-rw-r--r--lib/libkeynote/testsuite/auth31
-rw-r--r--lib/libkeynote/testsuite/auth411
-rw-r--r--lib/libkeynote/testsuite/test-assertion145
-rw-r--r--lib/libkeynote/testsuite/test-assertion27
-rw-r--r--lib/libkeynote/testsuite/test-assertion38
-rw-r--r--lib/libkeynote/testsuite/test-assertion45
-rw-r--r--lib/libkeynote/testsuite/test-assertion512
-rw-r--r--lib/libkeynote/testsuite/test-assertion67
-rw-r--r--lib/libkeynote/testsuite/test-assertion724
-rw-r--r--lib/libkeynote/testsuite/test-env10
46 files changed, 11142 insertions, 0 deletions
diff --git a/lib/libkeynote/HOWTO.add.crypto b/lib/libkeynote/HOWTO.add.crypto
new file mode 100644
index 00000000000..16abff224d7
--- /dev/null
+++ b/lib/libkeynote/HOWTO.add.crypto
@@ -0,0 +1,71 @@
+# $OpenBSD: HOWTO.add.crypto,v 1.1 1999/05/23 22:11:04 angelos Exp $
+
+This document describes how to add support for digital signature algorithms,
+hash functions, and ASCII encoding mechanisms in this implementation.
+
+For a signature algorithm:
+
+- Add the appropriate include files in keynote.h
+- Create one or more strings describing the signature algorithm
+ prefixes, and add those to keynote.h (the SIG_* definitions).
+- Add a definition for the algorithm in keynote.h (the
+ KEYNOTE_ALGORITHM_* definitions).
+- Define the algorithm public key prefixes, and add them to
+ signature.h (the *_HEX, *_HEX_LEN, *_BASE64, *_BASE64_LEN
+ definitions).
+- In aux.c, function keynote_keyhash(), add to the switch statement
+ a case handling the new algorithm; the return value is an integer,
+ and is used as an index into a hash table.
+- In signature.c:
+ - In keynote_free_key(), add code to free any memory allocated for
+ storing a key for the new algorithm.
+ - In keynote_get_sig_algorithm(), add code that checks whether a
+ signature string begins with one of the prefixes for the new
+ algorithm that were defined in keynote.h
+ - Similarly, in keynote_get_key_algorithm() for key strings, using
+ the key prefixes defined in signature.h
+ - In kn_decode_key(), add code that converts a bit string to
+ the new algorithm's structure for storing a key (use the DSA
+ code as a guide).
+ - Similarly for kn_encode_key()
+ - In keynote_keycompare(), add code that compares two keys and
+ returns RETURN_TRUE if they are equal, and RETURN_FALSE otherwise.
+ - In keynote_signverify_assertion, add code that verifies a
+ signature for the new algorithm.
+ - Likewise for signature generation in keynote_sign_assertion()
+- In keynote-keygen.c, replicate the code for DSA key generation to
+ support the new algorithm.
+
+For a hash algorithm:
+
+- Add the necessary include files in keynote.h
+- Add a KEYNOTE_HASH_* definition for the algorithm in signature.h
+- In signature.h, if the length of the new hash function's result is
+ more than LARGEST_HASH_SIZE (currently 20 bytes, for SHA1), then
+ replace that value with the new function's hash result length.
+- In signature.c:
+ - In keynote_sigverify_assertion(), add code in the switch statement
+ for generating a hash of the assertion and the signature algorithm
+ name (use the SHA1 code as an example).
+ - Likewise in keynote_sign_assertion()
+
+For an ASCII-encoding algorithm:
+
+- Add the necessary include files in keynote.h
+- Add additional SIG_* definitions in keynote.h
+- Add an ENCODING_* definition in keynote.h
+- Add additional key prefix string definitions in signature.h
+- In signature.c:
+ - In keynote_get_sig_algorithm(), add code for detecting signatures
+ with this encoding.
+ - Likewise for keys in keynote_get_key_algorithm()
+ - In kn_decode_key(), add code in the switch statement for decoding
+ ASCII-encoded keys.
+ - Likewise in kn_encode_key() for encoding keys.
+ - Likewise in keynote_sigverify_assertion() for decoding signatures.
+ - Add the necessary checks in keynote_sign_assertion() for handling
+ the new encoding, and code in the switch statement for doing the
+ encoding of the signature.
+- Add the necessary checks in keynote-keygen.c for handling the
+ new algorithm.
+
diff --git a/lib/libkeynote/LICENSE b/lib/libkeynote/LICENSE
new file mode 100644
index 00000000000..eb5d22d59be
--- /dev/null
+++ b/lib/libkeynote/LICENSE
@@ -0,0 +1,21 @@
+/* $OpenBSD: LICENSE,v 1.1 1999/05/23 22:11:07 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
diff --git a/lib/libkeynote/Makefile b/lib/libkeynote/Makefile
new file mode 100644
index 00000000000..a39407f390b
--- /dev/null
+++ b/lib/libkeynote/Makefile
@@ -0,0 +1,31 @@
+# $OpenBSD: Makefile,v 1.1 1999/05/23 22:11:04 angelos Exp $
+
+LIB= keynote
+MAN= man/keynote.3 man/keynote.4
+
+CFLAGS+= -DCRYPTO
+LEXFLAGS = -Cr -Pkn -s -i
+YACCFLAGS = -d -p kn -b k
+
+HDRS= keynote.h
+SRCS= k.tab.c lex.kn.c environment.c parse_assertion.c signature.c aux.c \
+ base64.c
+
+CLEANFILES+= k.tab.c lex.kn.c k.tab.h
+
+k.tab.c: keynote.y environment.h signature.h
+ $(YACC) $(YACCFLAGS) keynote.y
+
+lex.kn.c: keynote.l k.tab.h environment.h assertion.h signature.h
+ $(LEX.l) $(LEXFLAGS) keynote.l
+
+includes:
+ @cd ${.CURDIR}; for i in $(HDRS); do \
+ j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \
+ ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 $$i \
+ ${DESTDIR}/usr/include"; \
+ echo $$j; \
+ eval "$$j"; \
+ done
+
+.include <bsd.lib.mk>
diff --git a/lib/libkeynote/Makefile.dist b/lib/libkeynote/Makefile.dist
new file mode 100644
index 00000000000..b893d505050
--- /dev/null
+++ b/lib/libkeynote/Makefile.dist
@@ -0,0 +1,180 @@
+#
+# The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+#
+# This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+# in April-May 1998
+#
+# Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+#
+# Permission to use, copy, and modify this software without fee
+# is hereby granted, provided that this entire notice is included in
+# all copies of any software which is or includes a copy or
+# modification of this software.
+#
+# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+# IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+# PURPOSE.
+
+VERSION = 2-beta2
+DISTFILE = keynote-${VERSION}.tar.gz
+KNSUBDIR = KeyNote-${VERSION}
+
+RANLIB = ranlib
+MKDIR = mkdir
+YACC = yacc
+#YACC = bison
+TRUE = true
+LEX = flex
+TAR = tar
+CC = gcc
+RM = rm
+AR = ar
+NROFF = nroff
+
+TARFLAGS = -cvzf ${DISTFILE}
+YACCFLAGS2 = -d -p kv -b z
+YACCFLAGS = -d -p kn -b k
+LEXFLAGS2 = -Pkv -s -i
+LEXFLAGS = -Cr -Pkn -s -i
+CFLAGS = -O2 #-Wall -g
+RMFLAGS2 = -rf
+RMFLAGS = -f
+NROFFFLAGS = -mandoc
+
+# SSLeay/OpenSSL pointers
+SSLINC = -I/usr/local/include -I/usr/local/ssl/include \
+ -I/usr/local/openssl/include
+SSLLIB = -L/usr/lib -L/usr/local/lib -L/usr/local/ssl/lib \
+ -L/usr/local/openssl/lib -L/usr/local/openssl/ -lcrypto
+
+# No-crypto compile/link flags and definitions
+NOCRYPTODEFS = #-DPGPLIB -DNO_SNPRINTF -DNEED_GETOPT -DPILOT
+NOCRYPTOINC = -I.
+NOCRYPTOLIBS = -L. -lkeynote -lm
+
+# Final compile/link flags and definitions
+DEFS = -DCRYPTO ${NOCRYPTODEFS}
+INC = $(SSLINC) ${NOCRYPTOINC}
+LIBS = ${NOCRYPTOLIBS} ${SSLLIB}
+
+TARGET = libkeynote.a
+TARGET2 = keynote-verify
+TARGET3 = keynote-sign
+TARGET4 = keynote-sigver
+TARGET5 = keynote-keygen
+
+#GETOPT = getopt.o
+OBJS = k.tab.o lex.kn.o environment.o parse_assertion.o \
+ signature.o aux.o base64.o $(GETOPT)
+OBJS2 = z.tab.o lex.kv.o keynote-verify.o
+OBJS3 = keynote-sign.o
+OBJS4 = keynote-sigver.o
+OBJS5 = keynote-keygen.o
+
+crypto: all
+
+nocrypto:
+ ${MAKE} LIBS="${NOCRYPTOLIBS}" INC="${NOCRYPTOINC}" \
+ DEFS="${NOCRYPTODEFS}"
+
+all: $(TARGET) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5)
+
+library: $(TARGET)
+
+$(TARGET): $(OBJS)
+ $(AR) -cvr $(TARGET) $(OBJS)
+ $(RANLIB) $(TARGET)
+
+$(TARGET2): $(TARGET) $(OBJS2)
+ $(CC) $(CFLAGS) -o $(TARGET2) $(OBJS2) $(LIBS)
+
+$(TARGET3): $(TARGET) $(OBJS3)
+ $(CC) $(CFLAGS) -o $(TARGET3) $(OBJS3) $(LIBS)
+
+$(TARGET4): $(TARGET) $(OBJS4)
+ $(CC) $(CFLAGS) -o $(TARGET4) $(OBJS4) $(LIBS)
+
+$(TARGET5): $(TARGET) $(OBJS5)
+ $(CC) $(CFLAGS) -o $(TARGET5) $(OBJS5) $(LIBS)
+
+k.tab.c: keynote.y environment.h signature.h
+ $(YACC) $(YACCFLAGS) keynote.y
+
+z.tab.c: keynote-ver.y keynote.h
+ $(YACC) $(YACCFLAGS2) keynote-ver.y
+
+lex.kn.c: keynote.l k.tab.h environment.h assertion.h signature.h
+ $(LEX) $(LEXFLAGS) keynote.l
+
+lex.kv.c: keynote-ver.l z.tab.h keynote.h
+ $(LEX) $(LEXFLAGS2) keynote-ver.l
+
+.c.o:
+ $(CC) $(CFLAGS) $(DEFS) $(INC) -c $<
+
+aux.c: environment.h signature.h
+parse_assertion.c: assertion.h environment.h signature.h
+environment.c: environment.h
+keynote-verify.c: keynote.h
+environment.h: keynote.h
+assertion.h: keynote.h
+signature.h: assertion.h
+signature.c: signature.h
+keynote-keygen.c: signature.h
+keynote-sign.c: signature.h
+keynote-sigver.c: signature.h
+base64.c: keynote.h
+
+clean:
+ $(RM) $(RMFLAGS) $(OBJS) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5)
+ $(RM) $(RMFLAGS) a.out *.core *~ */*~
+
+cleandir: cleanall
+
+cleanall: clean
+ $(RM) $(RMFLAGS) *.o k.tab.c lex.kn.c k.tab.h z.tab.c z.tab.h
+ $(RM) $(RMFLAGS) lex.kv.c y.output z.output ${DISTFILE}
+ $(RM) $(RMFLAGS) $(TARGET) $(TARGET2) $(TARGET3)
+ $(RM) $(RMFLAGS) $(TARGET4) $(TARGET5) man/*.0
+
+test: all
+ ./$(TARGET2) -e testsuite/test-env \
+ -r false,maybe,probably,true \
+ -k testsuite/auth1 -k testsuite/auth2 -k testsuite/auth3 \
+ -k testsuite/auth4 \
+ -l testsuite/test-assertion1 -l testsuite/test-assertion2 \
+ -l testsuite/test-assertion3 -l testsuite/test-assertion4 \
+ -l testsuite/test-assertion5 -l testsuite/test-assertion6 \
+ -l testsuite/test-assertion7 || ${TRUE}
+
+manpages: mankeynote mansystem mansign manver mansigver mankeygen
+
+mankeynote:
+ ${NROFF} ${NROFFFLAGS} man/keynote.3 > man/keynote.0
+
+mansystem:
+ ${NROFF} ${NROFFFLAGS} man/keynote.4 > man/keynote-system.0
+
+mansign:
+ ${NROFF} ${NROFFFLAGS} man/keynote-sign.1 > man/keynote-sign.0
+
+mansigver:
+ ${NROFF} ${NROFFFLAGS} man/keynote-sigver.1 > man/keynote-sigver.0
+
+manver:
+ ${NROFF} ${NROFFFLAGS} man/keynote-verify.1 > man/keynote-verify.0
+
+mankeygen:
+ ${NROFF} ${NROFFFLAGS} man/keynote-keygen.1 > man/keynote-keygen.0
+
+distribution: test cleanall manpages
+ ${MKDIR} ${KNSUBDIR}
+ $(TAR) cf - . | (cd ${KNSUBDIR}; ${TAR} xf -)
+ ${RM} ${RMFLAGS2} ${KNSUBDIR}/CVS ${KNSUBDIR}/testsuite/CVS \
+ ${KNSUBDIR}/Misc/CVS ${KNSUBDIR}/${KNSUBDIR} \
+ ${KNSUBDIR}/.cvsignore ${KNSUBDIR}/man/CVS \
+ ${KNSUBDIR}/man/.cvsignore ${KNSUBDIR}/doc/CVS
+ $(TAR) $(TARFLAGS) ${KNSUBDIR}
+ ${RM} ${RMFLAGS2} ${KNSUBDIR}
diff --git a/lib/libkeynote/Misc/getopt.c b/lib/libkeynote/Misc/getopt.c
new file mode 100644
index 00000000000..4e12b012775
--- /dev/null
+++ b/lib/libkeynote/Misc/getopt.c
@@ -0,0 +1,83 @@
+/* $OpenBSD: getopt.c,v 1.1 1999/05/23 22:11:07 angelos Exp $ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/*** getopt
+ *
+ * This function is the public domain version of getopt, the command
+ * line argument processor, and hence is NOT copyrighted by Microsoft,
+ * IBM, or AT&T.
+ */
+
+#define ERR(s, c) if(opterr){\
+ (void) fputs(argv[0], stderr);\
+ (void) fputs(s, stderr);\
+ (void) fputc(c, stderr);\
+ (void) fputc('\n', stderr);}
+
+int opterr = 1; /* flag:error message on unrecognzed options */
+int optind = 1; /* last touched cmdline argument */
+int optopt; /* last returned option */
+char *optarg; /* argument to optopt */
+int getopt(int argc, char **argv, char *opts);
+
+/* int argc is the number of arguments on cmdline */
+/* char **argv is the pointer to array of cmdline arguments */
+/* char *opts is the string of all valid options */
+/* each char case must be given; options taking an arg are followed by =
+':' */
+int getopt(int argc, char **argv, char *opts)
+{
+ static int sp = 1;
+ register int c;
+ register char *cp;
+ if(sp == 1)
+ /* check for end of options */
+ if(optind >= argc ||
+ (argv[optind][0] != '/' &&
+ argv[optind][0] != '-') ||
+ argv[optind][1] == '\0')
+ return(EOF);
+ else if(!strcmp(argv[optind], "--")) {
+ optind++;
+ return(EOF);
+ }
+ optopt = c = argv[optind][sp];
+ if(c == ':' || (cp=strchr(opts, c)) == NULL) {
+ /* if arg sentinel as option or other invalid option,
+ handle the error and return '?' */
+ ERR(": illegal option -- ", (char)c);
+ if(argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ return('?');
+ }
+ if(*++cp == ':') {
+ /* if option is given an argument... */
+ if(argv[optind][sp+1] != '\0')
+ /* and the OptArg is in that CmdLineArg, return it... */
+ optarg = &argv[optind++][sp+1];
+ else if(++optind >= argc) {
+ /* but if the OptArg isn't there and the next CmdLineArg
+ isn't either, handle the error... */
+ ERR(": option requires an argument -- ", (char)c);
+ sp = 1;
+ return('?');
+ } else
+ /* but if there is another CmdLineArg there, return that */
+ optarg = argv[optind++];
+ /* and set up for the next CmdLineArg */
+ sp = 1;
+ } else {
+ /* no arg for this opt, so null arg and set up for next option */
+ if(argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return(c);
+}
diff --git a/lib/libkeynote/Misc/getopt.h b/lib/libkeynote/Misc/getopt.h
new file mode 100644
index 00000000000..17211043f1f
--- /dev/null
+++ b/lib/libkeynote/Misc/getopt.h
@@ -0,0 +1,6 @@
+/* $OpenBSD: getopt.h,v 1.1 1999/05/23 22:11:07 angelos Exp $ */
+
+extern int opterr; /* flag:error message on unrecognzed options */
+extern int optind; /* last touched cmdline argument */
+extern char *optarg; /* argument to optopt */
+int getopt(int argc, char **argv, char *opts);
diff --git a/lib/libkeynote/Misc/keynote.btm b/lib/libkeynote/Misc/keynote.btm
new file mode 100644
index 00000000000..434c5286420
--- /dev/null
+++ b/lib/libkeynote/Misc/keynote.btm
@@ -0,0 +1,14 @@
+#define keynote1_width 32
+#define keynote1_height 32
+static unsigned char keynote1_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0xec, 0xff, 0x01, 0x00, 0xc4, 0xff, 0x01, 0x00, 0xec, 0xff, 0x00, 0x00,
+ 0xfc, 0x90, 0x00, 0x00, 0x78, 0xd0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x1f, 0x00, 0x10, 0x00, 0x10, 0x00,
+ 0xd0, 0xff, 0x3f, 0x00, 0x50, 0x00, 0x20, 0x00, 0x50, 0xff, 0x2f, 0x00,
+ 0x50, 0x00, 0x20, 0x00, 0x50, 0xff, 0x23, 0x00, 0x50, 0x00, 0x20, 0x00,
+ 0x50, 0xff, 0x2f, 0x00, 0x50, 0x00, 0x20, 0x00, 0x50, 0xff, 0x27, 0x00,
+ 0x50, 0x00, 0x20, 0x00, 0x50, 0x7f, 0x20, 0x00, 0x50, 0x00, 0x20, 0x00,
+ 0x50, 0x00, 0x20, 0x00, 0x50, 0x00, 0x20, 0x00, 0x50, 0x00, 0x20, 0x00,
+ 0x50, 0x00, 0x20, 0x00, 0x50, 0x00, 0x20, 0x00, 0x70, 0x00, 0x20, 0x00,
+ 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/lib/libkeynote/Misc/keynote.gif b/lib/libkeynote/Misc/keynote.gif
new file mode 100644
index 00000000000..577ca8c5f3e
--- /dev/null
+++ b/lib/libkeynote/Misc/keynote.gif
Binary files differ
diff --git a/lib/libkeynote/README b/lib/libkeynote/README
new file mode 100644
index 00000000000..4eba6dcbe47
--- /dev/null
+++ b/lib/libkeynote/README
@@ -0,0 +1,97 @@
+# $OpenBSD: README,v 1.1 1999/05/23 22:11:03 angelos Exp $
+
+This is release 2-beta2 of the KeyNote trust management library reference
+implementation.
+
+For details on the KeyNote spec, read the file keynote-spec, included in
+this distribution (in the doc/ directory).
+
+To build the distribution, just type "make" or "make crypt". To test the
+distribution, type "make test". The query should evaluate to "true" (look
+at the last few lines of output). To build without crypto support, use
+"make nocrypto".
+
+Compile tips:
+- You need the SSLeay/OpenSSL library if you compile with crypto
+ (default), version 0.8.1b or later. You can find it in various
+ crypto software repositories, or at:
+ ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/
+
+ OpenSSL can be found at:
+ http://www.openssl.com/
+
+ Edit this distribution's Makefile, changing the variables SSLINC and
+ SSLLIB to reflect the location of the include files and libraries
+ respectively for SSLeay/OpenSSL.
+
+- Similarly, if you compile with -DPGPLIB you will need PGPlib-1.1
+ from ftp://dslab1.cs.uit.no/pub/PGPlib-1.1.tar.gz
+ ** Notice: there is no support for PGPLIB yet **
+
+ Make sure PGPINC and PGPLIB (in Makefile) point at the right
+ locations for the include files and the library respectively.
+
+- You may need to add support for initialization of the random
+ generator routines. There is currently support for most BSDs and
+ Linux. Look in keynote-keygen.c and environment.c for calls to
+ RAND_seed(). Bear in mind that you need high-quality
+ (cryptographic-grade) randomness.
+
+- If your system does not have snprintf(), uncomment the -DNO_SNPRINTF
+ in the Makefile (NOCRYPTODEFS variable).
+
+- If your system does not have getopt(), move the files getopt.c and
+ getopt.h from Misc/ and uncomment the GETOPT line in the Makefile, and
+ enable the -DNEED_GETOPT flag in NOCRYPTODEFS (you do not need to
+ for Windows).
+
+- For Windows, you should be able to compile using Visual C++ without
+ too much trouble (thanks to Dave Clark for testing release 0.1). You
+ can get a copy of a regular expression library from the KeyNote web
+ page (see below).
+
+The Makefile creates the libkeynote.a library and the keynote-verify,
+keynote-keygen, keynote-sigver, and keynote-sign programs. There's a
+man page for the library calls (keynote.3) and one for each of the
+utilities in the man/ directory. There is also a man page about KeyNote
+itself (keynote.4), which contains some text from the spec.
+
+To view them, use:
+
+ nroff -mandoc keynote.3 | more
+ nroff -mandoc keynote.4 | more
+ nroff -mandoc keynote-verify.1 | more
+ nroff -mandoc keynote-keygen.1 | more
+ nroff -mandoc keynote-sign.1 | more
+ nroff -mandoc keynote-sigver.1 | more
+
+Alternatively, you can just install them in your manpath. If your
+nroff does not support the -mandoc flag, use -man instead. For those
+systems that do not have nroff, the text version of the man pages are
+provided as well (the files with .0 suffixes in the same directory).
+
+The keynote-verify program can be used to verify a request, given a
+set of assertions and an environment file. The directory testsuite/
+has some examples assertions. The keynote-keygen program can
+be used to generate keys. The keynote-sign and keynote-sigver can be
+used to sign assertions, and verify signed assertions respectively.
+
+The file base64.c was taken from the OpenBSD libc and was slightly
+modified.
+
+Read the TODO file to see what's missing (and eventually coming).
+
+When in doubt on how to use a library call (despite the man pages),
+consult the implementation of the various utilities.
+
+For any questions, comments, bug reports, praise, or anything else,
+contact us at keynote@research.att.com
+
+There is also a users mailing list at keynote-users@nsa.research.att.com
+To subscribe, send a message to majordomo@nsa.research.att.com with the word
+"subscribe keynote-users" (without the quotes) in the message body.
+
+Finally, there is a web page for KeyNote at
+ http://www.cis.upenn.edu/~keynote
+
+Angelos D. Keromytis
diff --git a/lib/libkeynote/TODO b/lib/libkeynote/TODO
new file mode 100644
index 00000000000..7675ef9adbe
--- /dev/null
+++ b/lib/libkeynote/TODO
@@ -0,0 +1,14 @@
+# $OpenBSD: TODO,v 1.1 1999/05/23 22:11:03 angelos Exp $
+
+Short term TODOs:
+ - More interesting/comprehensive testsuite
+ - Add the proper RFC reference to the manpages and README
+ - Write key/signature algorithm draft(s)
+ - autoconf
+ - Document X509 support
+
+Long term TODOs:
+ - Some sort of tcl/tk GUI
+ - PalmPilot support
+ - PGPlib support
+ - ElGamal support
diff --git a/lib/libkeynote/assertion.h b/lib/libkeynote/assertion.h
new file mode 100644
index 00000000000..d559e52beeb
--- /dev/null
+++ b/lib/libkeynote/assertion.h
@@ -0,0 +1,106 @@
+/* $OpenBSD: assertion.h,v 1.1 1999/05/23 22:11:03 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef __ASSERTION_H__
+#define __ASSERTION_H__
+
+#include "keynote.h"
+
+struct keylist
+{
+ int key_alg;
+ void *key_key;
+ char *key_stringkey;
+ struct keylist *key_next;
+};
+
+struct assertion
+{
+ void *as_authorizer;
+ char *as_buf;
+ char *as_signature;
+ char *as_authorizer_string_s;
+ char *as_authorizer_string_e;
+ char *as_keypred_s;
+ char *as_keypred_e;
+ char *as_conditions_s;
+ char *as_conditions_e;
+ char *as_signature_string_s;
+ char *as_signature_string_e;
+ char *as_comment_s;
+ char *as_comment_e;
+ char *as_startofsignature;
+ char *as_allbutsignature;
+ int as_id;
+ int as_signeralgorithm;
+ int as_result;
+ int as_error;
+ u_char as_flags;
+ u_char as_internalflags;
+ char as_kresult;
+ char as_sigresult;
+ struct keylist *as_keylist;
+ struct environment *as_env;
+ struct assertion *as_next;
+};
+
+/* Internal flags */
+#define ASSERT_IFLAG_WEIRDLICS 0x0001 /* Needs Licensees re-processing */
+#define ASSERT_IFLAG_WEIRDAUTH 0x0002 /* Needs Authorizer re-processing */
+#define ASSERT_IFLAG_WEIRDSIG 0x0004 /* Needs Signature re-processing */
+#define ASSERT_IFLAG_NEEDPROC 0x0008 /* Needs "key field" processing */
+#define ASSERT_IFLAG_PROCESSED 0x0010 /* Handled repositioning already */
+
+extern struct assertion *keynote_current_assertion;
+
+#define KRESULT_UNTOUCHED 0
+#define KRESULT_IN_PROGRESS 1 /* For cycle detection */
+#define KRESULT_DONE 2
+
+#define KEYWORD_VERSION 1
+#define KEYWORD_LOCALINIT 2
+#define KEYWORD_AUTHORIZER 3
+#define KEYWORD_LICENSEES 4
+#define KEYWORD_CONDITIONS 5
+#define KEYWORD_SIGNATURE 6
+#define KEYWORD_COMMENT 7
+
+#define KEYNOTE_FLAG_EXPORTALL 0x1
+
+#define LEXTYPE_CHAR 0x1
+
+struct keylist *keynote_keylist_find(struct keylist *, char *);
+struct assertion *keynote_parse_assertion(char *, int, int);
+int keynote_evaluate_authorizer(struct assertion *, int);
+struct assertion *keynote_find_assertion(void *, int, int);
+int keynote_evaluate_assertion(struct assertion *);
+int keynote_parse_keypred(struct assertion *, int);
+int keynote_keylist_add(struct keylist **, char *);
+int keynote_add_htable(struct assertion *, int);
+void keynote_free_assertion(struct assertion *);
+void keynote_keylist_free(struct keylist *);
+int keynote_in_authorizers(void *, int);
+char *keynote_get_private_key(char *);
+int keynote_evaluate_query(void);
+int keynote_lex_add(void *, int);
+void keynote_lex_remove(void *);
+#endif /* __ASSERTION_H__ */
diff --git a/lib/libkeynote/aux.c b/lib/libkeynote/aux.c
new file mode 100644
index 00000000000..18108c26ea5
--- /dev/null
+++ b/lib/libkeynote/aux.c
@@ -0,0 +1,511 @@
+/* $OpenBSD: aux.c,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#ifndef PILOT
+#include <time.h>
+#endif /* PILOT */
+#include "environment.h"
+#include "signature.h"
+
+/*
+ * Get some sort of key-hash for hash table indexing purposes.
+ */
+static int
+keynote_keyhash(void *key, int alg)
+{
+ struct keynote_binary *bn;
+ unsigned int res = 0, i;
+#ifdef CRYPTO
+ DSA *dsa;
+ RSA *rsa;
+#endif /* CRYPTO */
+
+ if (key == (void *) NULL)
+ return 0;
+
+ switch (alg)
+ {
+#ifdef CRYPTO
+ case KEYNOTE_ALGORITHM_DSA:
+ dsa = (DSA *) key;
+ res += BN_mod_word(dsa->p, HASHTABLESIZE);
+ res += BN_mod_word(dsa->q, HASHTABLESIZE);
+ res += BN_mod_word(dsa->g, HASHTABLESIZE);
+ res += BN_mod_word(dsa->pub_key, HASHTABLESIZE);
+ return res % HASHTABLESIZE;
+
+ case KEYNOTE_ALGORITHM_RSA:
+ rsa = (RSA *) key;
+ res += BN_mod_word(rsa->n, HASHTABLESIZE);
+ res += BN_mod_word(rsa->e, HASHTABLESIZE);
+ return res % HASHTABLESIZE;
+
+ case KEYNOTE_ALGORITHM_X509: /* RSA-specific */
+ rsa = (RSA *) key;
+ res += BN_mod_word(rsa->n, HASHTABLESIZE);
+ res += BN_mod_word(rsa->e, HASHTABLESIZE);
+ return res % HASHTABLESIZE;
+#endif /* CRYPTO */
+
+ case KEYNOTE_ALGORITHM_BINARY:
+ bn = (struct keynote_binary *) key;
+ for (i = 0; i < bn->bn_len; i++)
+ res = (res + ((unsigned char) bn->bn_key[i])) % HASHTABLESIZE;
+
+ return res;
+
+ case KEYNOTE_ALGORITHM_NONE:
+ return keynote_stringhash(key, HASHTABLESIZE);
+
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Return RESULT_TRUE if key appears in the action authorizers.
+ */
+int
+keynote_in_action_authorizers(void *key, int algorithm)
+{
+ struct keylist *kl, *kl2;
+ void *s;
+ int alg;
+
+ if (algorithm == KEYNOTE_ALGORITHM_UNSPEC)
+ {
+ kl2 = keynote_keylist_find(keynote_current_assertion->as_keylist, key);
+ if (kl2 == (struct keylist *) NULL)
+ return RESULT_FALSE; /* Shouldn't ever happen */
+
+ s = kl2->key_key;
+ alg = kl2->key_alg;
+ }
+ else
+ {
+ s = key;
+ alg = algorithm;
+ }
+
+ for (kl = keynote_current_session->ks_action_authorizers;
+ kl != (struct keylist *) NULL;
+ kl = kl->key_next)
+ if (kl->key_alg == alg)
+ if (keynote_keycompare(kl->key_key, s, alg) == RESULT_TRUE)
+ return RESULT_TRUE;
+
+ return RESULT_FALSE;
+}
+
+/*
+ * Add a key to the keylist. Return RESULT_TRUE on success, -1 (and set
+ * keynote_errno) otherwise. We are not supposed to make a copy of the
+ * argument.
+ */
+int
+keynote_keylist_add(struct keylist **keylist, char *key)
+{
+ struct keynote_deckey dc;
+ struct keylist *kl;
+
+ if (keylist == (struct keylist **) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ kl = (struct keylist *) calloc(1, sizeof(struct keylist));
+ if (kl == (struct keylist *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (kn_decode_key(&dc, key, KEYNOTE_PUBLIC_KEY) != 0)
+ {
+ free(kl);
+ return -1;
+ }
+
+ kl->key_key = dc.dec_key;
+ kl->key_alg = dc.dec_algorithm;
+ kl->key_stringkey = key;
+ kl->key_next = *keylist;
+ *keylist = kl;
+ return RESULT_TRUE;
+}
+
+/*
+ * Remove an action authorizer.
+ */
+int
+kn_remove_authorizer(int sessid, char *key)
+{
+ struct keynote_session *ks;
+ struct keylist *kl, *kl2;
+
+ keynote_errno = 0;
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ ks = keynote_current_session;
+
+ /* If no action authorizers present */
+ if ((kl = ks->ks_action_authorizers) == (struct keylist *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+
+ /* First in list */
+ if (!strcmp(kl->key_stringkey, key))
+ {
+ ks->ks_action_authorizers = kl->key_next;
+ kl->key_next = (struct keylist *) NULL;
+ keynote_keylist_free(kl);
+ return 0;
+ }
+
+ for (; kl->key_next != (struct keylist *) NULL; kl = kl->key_next)
+ if (!strcmp(kl->key_stringkey, key))
+ {
+ kl2 = kl->key_next;
+ kl->key_next = kl2->key_next;
+ kl2->key_next = (struct keylist *) NULL;
+ keynote_keylist_free(kl2);
+ return 0;
+ }
+
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+}
+
+/*
+ * Add an action authorizer.
+ */
+int
+kn_add_authorizer(int sessid, char *key)
+{
+ char *stringkey;
+
+ keynote_errno = 0;
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ stringkey = strdup((char *) key);
+ if (stringkey == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (keynote_keylist_add(&(keynote_current_session->ks_action_authorizers),
+ stringkey) == -1)
+ {
+ free(stringkey);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Find a keylist entry based on the key_stringkey entry.
+ */
+struct keylist *
+keynote_keylist_find(struct keylist *kl, char *s)
+{
+ for (; kl != (struct keylist *) NULL; kl = kl->key_next)
+ if (!strcmp(kl->key_stringkey, s))
+ return kl;
+
+ return kl;
+}
+
+/*
+ * Free keylist list.
+ */
+void
+keynote_keylist_free(struct keylist *kl)
+{
+ struct keylist *kl2;
+
+ while (kl != (struct keylist *) NULL)
+ {
+ kl2 = kl->key_next;
+ free(kl->key_stringkey);
+ keynote_free_key(kl->key_key, kl->key_alg);
+ free(kl);
+ kl = kl2;
+ }
+}
+
+/*
+ * Find the num-th assertion given the authorizer. Return NULL if not found.
+ */
+struct assertion *
+keynote_find_assertion(void *authorizer, int num, int algorithm)
+{
+ struct assertion *as;
+ unsigned int h;
+
+ if (authorizer == (char *) NULL)
+ return (struct assertion *) NULL;
+
+ h = keynote_keyhash(authorizer, algorithm);
+ for (as = keynote_current_session->ks_assertion_table[h];
+ as != (struct assertion *) NULL;
+ as = as->as_next)
+ if ((as->as_authorizer != (void *) NULL) &&
+ (as->as_signeralgorithm == algorithm))
+ if (keynote_keycompare(authorizer, as->as_authorizer, algorithm) ==
+ RESULT_TRUE)
+ if (num-- == 0)
+ return as;
+
+ return (struct assertion *) NULL;
+}
+
+/*
+ * Add an assertion to the hash table. Return RESULT_TRUE on success,
+ * ERROR_MEMORY for memory failure, ERROR_SYNTAX if some problem with
+ * the assertion is detected.
+ */
+int
+keynote_add_htable(struct assertion *as, int which)
+{
+ char *hashname;
+ u_int i;
+
+ if (as == (struct assertion *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (!which)
+ hashname = as->as_authorizer_string_s;
+ else
+ hashname = as->as_authorizer;
+
+ if (hashname == (char *) NULL)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ i = keynote_keyhash(hashname, as->as_signeralgorithm);
+ as->as_next = keynote_current_session->ks_assertion_table[i];
+ keynote_current_session->ks_assertion_table[i] = as;
+ return RESULT_TRUE;
+}
+
+/*
+ * Parse and store an assertion in the internal hash table.
+ * Return the result of the evaluation, if doing early evaluation.
+ * If an error was encountered, set keynote_errno.
+ */
+int
+kn_add_assertion(int sessid, char *asrt, int len, int assertion_flags)
+{
+ struct assertion *as;
+
+ keynote_errno = 0;
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ as = keynote_parse_assertion(asrt, len, assertion_flags);
+ if ((as == (struct assertion *) NULL) || (keynote_errno != 0))
+ {
+ if (keynote_errno == 0)
+ keynote_errno = ERROR_SYNTAX;
+
+ return -1;
+ }
+
+ as->as_id = keynote_current_session->ks_assertioncounter++;
+
+ /* Check for wrap around...there has to be a better solution to this */
+ if (keynote_current_session->ks_assertioncounter < 0)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ if (keynote_add_htable(as, 0) != RESULT_TRUE)
+ {
+ keynote_free_assertion(as);
+ return -1;
+ }
+
+ as->as_internalflags |= ASSERT_IFLAG_NEEDPROC;
+ return as->as_id;
+}
+
+/*
+ * Remove an assertion from the hash table.
+ */
+static int
+keynote_remove_assertion(int sessid, int assertid, int deleteflag)
+{
+ struct assertion *ht, *ht2;
+ int i;
+
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ for (i = 0; i < HASHTABLESIZE; i++)
+ {
+ ht = keynote_current_session->ks_assertion_table[i];
+ if (ht == (struct assertion *) NULL)
+ continue;
+
+ /* If first entry in bucket */
+ if (ht->as_id == assertid)
+ {
+ keynote_current_session->ks_assertion_table[i] = ht->as_next;
+ if (deleteflag)
+ keynote_free_assertion(ht);
+ return 0;
+ }
+
+ for (; ht->as_next != (struct assertion *) NULL; ht = ht->as_next)
+ if (ht->as_next->as_id == assertid) /* Got it */
+ {
+ ht2 = ht->as_next;
+ ht->as_next = ht2->as_next;
+ if (deleteflag)
+ keynote_free_assertion(ht2);
+ return 0;
+ }
+ }
+
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+}
+
+/*
+ * API wrapper for deleting assertions.
+ */
+int
+kn_remove_assertion(int sessid, int assertid)
+{
+ keynote_errno = 0;
+ return keynote_remove_assertion(sessid, assertid, 1);
+}
+
+/*
+ * Internally-used wrapper for removing but not deleting assertions.
+ */
+int
+keynote_sremove_assertion(int sessid, int assertid)
+{
+ return keynote_remove_assertion(sessid, assertid, 0);
+}
+
+/*
+ * Free an assertion structure.
+ */
+void
+keynote_free_assertion(struct assertion *as)
+{
+ if (as == (struct assertion *) NULL)
+ return;
+
+ if (as->as_buf != (char *) NULL)
+ free(as->as_buf);
+
+ if (as->as_signature != (char *) NULL)
+ free(as->as_signature);
+
+ if (as->as_env != (struct environment *) NULL)
+ keynote_env_cleanup(&(as->as_env), 1);
+
+ if (as->as_keylist != (struct keylist *) NULL)
+ keynote_keylist_free(as->as_keylist);
+
+ if (as->as_authorizer != (void *) NULL)
+ keynote_free_key(as->as_authorizer, as->as_signeralgorithm);
+
+ free(as);
+}
+
+/*
+ * Taken from "Compiler Design in C" by Aho.
+ */
+u_int
+keynote_stringhash(char *name, u_int size)
+{
+ unsigned int hash_val = 0;
+ unsigned int i;
+
+ if ((size == 0) || (size == 1))
+ return 0;
+
+ for (; *name; name++)
+ {
+ hash_val = (hash_val << 2) + *name;
+ if ((i = hash_val & 0x3fff))
+ hash_val = ((hash_val ^ (i >> 12)) & ~0x3fff);
+ }
+
+ return hash_val % size;
+}
diff --git a/lib/libkeynote/base64.c b/lib/libkeynote/base64.c
new file mode 100644
index 00000000000..51331ff8c21
--- /dev/null
+++ b/lib/libkeynote/base64.c
@@ -0,0 +1,348 @@
+/* $OpenBSD: base64.c,v 1.1 1999/05/23 22:11:06 angelos Exp $ */
+
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "keynote.h"
+
+#define Assert(Cond) if (!(Cond)) return -1;
+
+static const char Base64[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+kn_encode_base64(src, srclength, target, targsize)
+unsigned char const *src;
+unsigned int srclength;
+char *target;
+unsigned int targsize;
+{
+ unsigned int datalength = 0;
+ unsigned char input[3];
+ unsigned char output[4];
+ int i;
+
+ keynote_errno = 0;
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+kn_decode_base64(src, target, targsize)
+char const *src;
+unsigned char *target;
+unsigned int targsize;
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ keynote_errno = 0;
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ switch (state) {
+ case 0:
+ if (target) {
+ if (tarindex >= targsize)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if (tarindex >= targsize)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for (; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for (; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (-1);
+ }
+ }
+
+ return (tarindex);
+}
diff --git a/lib/libkeynote/doc/keynote-spec b/lib/libkeynote/doc/keynote-spec
new file mode 100644
index 00000000000..f59e9654363
--- /dev/null
+++ b/lib/libkeynote/doc/keynote-spec
@@ -0,0 +1,1562 @@
+# $OpenBSD: keynote-spec,v 1.1 1999/05/23 22:11:09 angelos Exp $
+
+Network Working Group Matt Blaze
+INTERNET DRAFT Joan Feigenbaum
+Expires in six months John Ioannidis
+ AT&T Labs - Research
+ Angelos D. Keromytis
+ U. of Pennsylvania
+ March 1999
+
+ The KeyNote Trust-Management System
+ Version 2
+ <draft-blaze-ietf-trustmgt-keynote-01.txt>
+
+Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of RFC2026.
+
+ Please direct comments to one of the authors (for the authors contact
+ information, see the end of this document), and/or to the
+ trustmgt@east.isi.edu mailing list.
+
+ Internet Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working Groups. Note that
+ other groups may also distribute working documents as Internet
+ Drafts.
+
+ Internet-Drafts draft documents are valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress".
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ Distribution of this memo is unlimited.
+
+Abstract
+
+ This memo describes version 2 of the KeyNote trust-management system.
+ It specifies the syntax and semantics of KeyNote `assertions,'
+ describes `action attribute' processing, and outlines the application
+ architecture into which a KeyNote implementation can be fit. The
+ KeyNote architecture and language are useful as building blocks for
+ the trust management aspects of a variety of Internet protocols and
+ services.
+
+
+1. Introduction
+
+ Trust management, introduced in the PolicyMaker system [BFL96], is a
+ unified approach to specifying and interpreting security policies,
+ credentials, and relationships; it allows direct authorization of
+ security-critical actions. A trust-management system provides
+ standard, general-purpose mechanisms for specifying application
+ security policies and credentials. Trust-management credentials
+ describe a specific delegation of trust and subsume the role of
+ public key certificates; unlike traditional certificates, which bind
+ keys to names, credentials can bind keys directly to the
+ authorization to perform specific tasks.
+
+ A trust-management system has five basic components:
+
+ * A language for describing `actions,' which are operations with
+ security consequences that are to be controlled by the system.
+
+ * A mechanism for identifying `principals,' which are entities that
+ can be authorized to perform actions.
+
+ * A language for specifying application `policies,' which govern the
+ actions that principals are authorized to perform.
+
+ * A language for specifying `credentials,' which allow principals
+ to delegate authorization to other principals.
+
+ * A `compliance checker,' which provides a service to applications
+ for determining how an action requested by principals should be
+ handled, given a policy and a set of credentials.
+
+ The trust-management approach has a number of advantages over other
+ mechanisms for specifying and controlling authorization, especially
+ when security policy is distributed over a network or is otherwise
+ decentralized.
+
+ Trust management unifies the notions of security policy, credentials,
+ access control, and authorization. An application that uses a trust-
+ management system can simply ask the compliance checker whether a
+ requested action should be allowed. Furthermore, policies and
+ credentials are written in standard languages that are shared by all
+ trust-managed applications; the security configuration mechanism for
+ one application carries exactly the same syntactic and semantic
+ structure as that of another, even when the semantics of the
+ applications themselves are quite different.
+
+ Trust-management policies are easy to distribute across networks,
+ helping to avoid the need for application-specific distributed policy
+ configuration mechanisms, access control lists, and certificate
+ parsers and interpreters.
+
+ For a general discussion of the use of trust management in
+ distributed system security, see [Bla99].
+
+ KeyNote is a simple and flexible trust-management system designed to
+ work well for a variety of large- and small- scale Internet-based
+ applications. It provides a single, unified language for both local
+ policies and credentials. KeyNote policies and credentials, called
+ `assertions,' contain predicates that describe the trusted actions
+ permitted by the holders of specific public keys. KeyNote assertions
+ are essentially small, highly-structured programs. A signed
+ assertion, which can be sent over an untrusted network, is also
+ called a `credential assertion.' Credential assertions, which also
+ serve the role of certificates, have the same syntax as policy
+ assertions but are also signed by the principal delegating the trust.
+
+ In KeyNote:
+
+ * Actions are specified as a collection of name-value pairs.
+
+ * Principal names can be any convenient string and can directly
+ represent cryptographic public keys.
+
+ * The same language is used for both policies and credentials.
+
+ * The policy and credential language is concise, highly expressive,
+ human readable and writable, and compatible with a variety of
+ storage and transmission media, including electronic mail.
+
+ * The compliance checker returns an application-configured `policy
+ compliance value' that describes how a request should be handled
+ by the application. Policy compliance values are always
+ positively derived from policy and credentials, facilitating
+ analysis of KeyNote-based systems.
+
+ * Compliance checking is efficient enough for high-performance and
+ real-time applications.
+
+ This document describes the KeyNote policy and credential assertion
+ language, the structure of KeyNote action descriptions, and the
+ KeyNote model of computation.
+
+ We assume that applications communicate with a locally trusted
+ KeyNote compliance checker via a `function call' style interface,
+ sending a collection of KeyNote policy and credential assertions plus
+ an action description as input and accepting the resulting policy
+ compliance value as output. However, the requirements of different
+ applications, hosts, and environments may give rise to a variety of
+ different interfaces to KeyNote compliance checkers; this document
+ does not aim to specify a complete compliance checker API.
+
+
+2. KeyNote Concepts
+
+ In KeyNote, the authority to perform trusted actions is associated
+ with one or more `principals.' A principal may be a physical entity,
+ a process in an operating system, a public key, or any other
+ convenient abstraction. KeyNote principals are identified by a
+ string called a `Principal Identifier.' In some cases, a Principal
+ Identifier will contain a cryptographic key interpreted by the
+ KeyNote system (e.g., for credential signature verification). In
+ other cases, Principal Identifiers may have a structure that is
+ opaque to KeyNote.
+
+ Principals perform two functions of concern to KeyNote: They request
+ `actions' and they issue `assertions.' Actions are any trusted
+ operations that an application places under KeyNote control.
+ Assertions delegate the authorization to perform actions to other
+ principals.
+
+ Actions are described to the KeyNote compliance checker in terms of a
+ collection of name-value pairs called an `action attribute set.' The
+ action attribute set is created by the invoking application. Its
+ structure and format are described in detail in Section 3 of this
+ document.
+
+ KeyNote provides advice to applications on the interpretation of
+ policy with regard to specific requested actions. Applications
+ invoke the KeyNote compliance checker by issuing a `query' containing
+ a proposed action attribute set and identifying the principal(s)
+ requesting it. The KeyNote system determines and returns an
+ appropriate `policy compliance value' from an ordered set of possible
+ responses.
+
+ The policy compliance value returned from a KeyNote query advises the
+ application how to process the requested action. In the simplest
+ case, the compliance value is Boolean (e.g., "reject" or "approve").
+ Assertions can also be written to select from a range of possible
+ compliance values, when appropriate for the application (e.g., "no
+ access", "restricted access", "full access"). Applications can
+ configure the relative ordering (from `weakest' to `strongest') of
+ compliance values at query time.
+
+ Assertions are the basic programming unit for specifying policy and
+ delegating authority. Assertions describe the conditions under which
+ a principal authorizes actions requested by other principals. An
+ assertion identifies the principal that made it, which other
+ principals are being authorized, and the conditions under which the
+ authorization applies. The syntax of assertions is given in Section
+ 4.
+
+ A special principal, whose identifier is "POLICY", provides the root
+ of trust in KeyNote. "POLICY" is therefore considered to be
+ authorized to perform any action.
+
+ Assertions issued by the "POLICY" principal are called `policy
+ assertions' and are used to delegate authority to otherwise untrusted
+ principals. The KeyNote security policy of an application consists
+ of a collection of policy assertions.
+
+ When a principal is identified by a public key, it can digitally sign
+ assertions and distribute them over untrusted networks for use by
+ other KeyNote compliance checkers. These signed assertions are also
+ called `credentials,' and serve a role similar to that of traditional
+ public key certificates. Policies and credentials share the same
+ syntax and are evaluated according to the same semantics. A
+ principal can therefore convert its policy assertions into
+ credentials simply by digitally signing them.
+
+ KeyNote is designed to encourage the creation of human-readable
+ policies and credentials that are amenable to transmission and
+ storage over a variety of media. Its assertion syntax is inspired by
+ the format of RFC822-style message headers [Cro82]. A KeyNote
+ assertion contains a sequence of sections, called `fields,' each of
+ which specifying one aspect of the assertion's semantics. Fields
+ start with an identifier at the beginning of a line and continue
+ until the next field is encountered. For example:
+
+ KeyNote-Version: 2
+ Comment: A simple, if contrived, email certificate for user mab
+ Local-Constants: ATT_CA_key = "RSA:acdfa1df1011bbac"
+ mab_key = "DSA:deadbeefcafe001a"
+ Authorizer: ATT_CA_key
+ Licensees: mab_key
+ Conditions: ((app_domain == "email") # valid for email only
+ && (address == "mab@research.att.com"));
+ Signature: "RSA-SHA1:f00f2244"
+
+ The meanings of the various sections are described in Sections 4 and
+ 5 of this document.
+
+ KeyNote semantics resolve the relationship between an application's
+ policy and actions requested by other principals, as supported by
+ credentials. The KeyNote compliance checker processes the assertions
+ against the action attribute set to determine the policy compliance
+ value of a requested action. These semantics are defined in Section
+ 5.
+
+ An important principle in KeyNote's design is `assertion
+ monotonicity'; the policy compliance value of an action is always
+ positively derived from assertions made by trusted principals.
+ Removing an assertion never results in increasing the compliance
+ value returned by KeyNote for a given query. The monotonicity
+ property can simplify the design and analysis of complex network-
+ based security protocols; network failures that prevent the
+ transmission of credentials can never result in spurious
+ authorization of dangerous actions.
+
+
+3. Action Attributes
+
+ Trusted actions to be evaluated by KeyNote are described by a
+ collection of name-value pairs called the `action attribute set.'
+ Action attributes are the mechanism by which applications communicate
+ requests to KeyNote and are the primary objects on which KeyNote
+ assertions operate. An action attribute set is passed to the KeyNote
+ compliance checker with each query.
+
+ Each action attribute consists of a name and a value. The semantics
+ of the names and values are not interpreted by KeyNote itself; they
+ vary from application to application and must be agreed upon by the
+ writers of applications and the writers of the policies and
+ credentials that will be used by them.
+
+ Action attribute names and values are represented by arbitrary-length
+ strings. KeyNote guarantees support of attribute names and values up
+ to 2048 characters long. The handling of longer attribute names or
+ values is not specified and is KeyNote- implementation-dependent.
+ Applications and assertions should therefore avoid depending on the
+ the use of attributes with names or values longer than 2048
+ characters. The length of an attribute value is represented by an
+ implementation-specific mechanism (e.g., NUL-terminated strings, an
+ explicit length field, etc.).
+
+ Attribute values are inherently untyped and are represented as
+ character strings by default. Attribute values may contain any non-
+ NUL ASCII character. Numeric attribute values should first be
+ converted to an ASCII text representation by the invoking
+ application, e.g., the value 1234.5 would be represented by the
+ string "1234.5".
+
+ Attribute names are of the form:
+
+ <AttributeID> ::= [a-zA-Z_][a-zA-Z0-9_]*
+
+ That is, an <AttributeID> begins with an alphabetic or underscore
+ character and can be followed by any number of alphanumerics and
+ underscores. Attribute names are case-sensitive.
+
+ The exact mechanism for passing the action attribute set to the
+ compliance checker is determined by the KeyNote implementation.
+ Depending on specific requirements, an implementation may provide a
+ mechanism for including the entire attribute set as an explicit
+ parameter of the query, or it may provide some form of callback
+ mechanism invoked as each attribute is dereferenced, e.g., for access
+ to kernel variables.
+
+ If an action attribute is not defined its value is considered to be
+ the empty string.
+
+ Attribute names beginning with the "_" character are reserved for use
+ by the KeyNote runtime environment and cannot be passed from
+ applications as part of queries. The following special attribute
+ names are used:
+
+ Name Purpose
+ ------------------------ ------------------------------------
+ _MIN_TRUST Lowest-order (minimum) compliance
+ value in query; see Section 5.1.
+
+ _MAX_TRUST Highest-order (maximum) compliance
+ value in query; see Section 5.1.
+
+ _VALUES Linearly ordered set of compliance
+ values in query; see Section 5.1.
+ Comma separated.
+
+ _ACTION_AUTHORIZERS Names of principals directly
+ authorizing action in query.
+ Comma separated.
+
+ In addition, attributes with names of the form "_<N>", where <N> is
+ an ASCII-encoded integer, are used by the regular expression matching
+ mechanism described in Section 5.
+
+ The assignment and semantics of any other attribute names beginning
+ with "_" is unspecified and implementation-dependent.
+
+ The names of other attributes in the action attribute set are not
+ specified by KeyNote but must be agreed upon by the writers of any
+ policies and credentials that are to inter-operate in a specific
+ KeyNote query evaluation.
+
+ By convention, the name of the application domain over which action
+ attributes should be interpreted is given in the attribute named
+ "app_domain". The IANA (or some other suitable authority) will
+ provide a registry of reserved app_domain names. The registry will
+ list the names and meanings of each application's attributes.
+
+ The app_domain convention helps to ensure that credentials are
+ interpreted as they were intended. An attribute with any given name
+ may be used in many different application domains but might have
+ different meanings in each of them. However, the use of a global
+ registry is not always required for small-scale, closed applications;
+ the only requirement is that the policies and credentials made
+ available to the KeyNote compliance checker interpret attributes
+ according to the same semantics assumed by the application that
+ created them.
+
+ For example, an email application might reserve the app_domain
+ "RFC822-EMAIL" and might use the attributes named "address" (the
+ email address of a message's sender), "name" (the human name of the
+ message sender), and "organization" (the organization name). The
+ values of these attributes would be derived in the obvious way from
+ the email message headers. The public key of the message's signer
+ would be given in the "_ACTION_AUTHORIZERS" attribute.
+
+ Note that "RFC822-EMAIL" is a hypothetical example; such a name may
+ or may not appear in the actual registry with these or different
+ attributes. (Indeed, we recognize that the reality of email security
+ is considerably more complex than this example might suggest.)
+
+
+4. KeyNote Assertion Syntax
+
+ In the following sections, the notation [X]* means zero or more
+ repetitions of character string X. The notation [X]+ means one or
+ more repetitions of X. Nonterminal grammar symbols are enclosed in
+ angled brackets. Quoted strings in grammar productions represent
+ terminals.
+
+4.1 Basic Structure
+
+ All KeyNote assertions are encoded in ASCII.
+
+ KeyNote assertions are divided into sections, called `fields,' that
+ serve various semantic functions. Each field starts with an
+ identifying label at the beginning of a line, followed by the ":"
+ character and the field's contents. There can be at most one field
+ per line.
+
+ A field may be continued over more than one line by indenting
+ subsequent lines with at least one ASCII SPACE or TAB character.
+ Whitespace (a SPACE, TAB, or NEWLINE character) separates tokens but
+ is otherwise ignored outside of quoted strings. Comments with a
+ leading octothorp character (see Section 4.2) may begin in any
+ column.
+
+ One mandatory field is required in all assertions:
+
+ Authorizer
+
+ Six optional fields may also appear:
+
+ Comment
+ Conditions
+ KeyNote-Version
+ Licensees
+ Local-Constants
+ Signature
+
+ All field names are case-insensitive. The "KeyNote-Version" field,
+ if present, appears first. The "Signature" field, if present,
+ appears last. Otherwise, fields may appear in any order. Each field
+ may appear at most once in any assertion.
+
+ Blank lines are not permitted in assertions. Multiple assertions
+ stored in a file (e.g., in application policy configurations),
+ therefore, can be separated from one another unambiguously by the use
+ of blank lines between them.
+
+4.2 Comments
+
+ The octothorp character ("#", ASCII 35 decimal) can be used to
+ introduce comments. Outside of quoted strings (see Section 4.3), all
+ characters from the "#" character through the end of the current line
+ are ignored. However, commented text is included in the computation
+ of assertion signatures (see Section 4.6.7).
+
+4.3 Strings
+
+ A `string' is a lexical object containing a sequence of characters.
+ Strings may contain any non-NUL characters, including newlines and
+ nonprinting characters. Strings may be given as literals, computed
+ from complex expressions, or dereferenced from attribute names.
+
+4.3.1 String Literals
+
+ A string literal directly represents the value of a string. String
+ literals must be quoted by preceding and following them with the
+ double-quote character (ASCII 34 decimal).
+
+ A printable character may be `escaped' inside a quoted string literal
+ by preceding it with the backslash character (ASCII 92 decimal)
+ (e.g., "like \"this\"."). This permits the inclusion of the double-
+ quote and backslash characters inside string literals.
+
+ A similar escape mechanism is also used to represent non-printable
+ characters. "\n" represents the newline character (ASCII character
+ 10 decimal), "\r" represents the carriage-return character (ASCII
+ character 13 decimal), "\t" represents the tab character (ASCII
+ character 9 decimal), and "\f" represents the form-feed character
+ (ASCII character 12 decimal). A backslash character followed by a
+ newline suppresses all subsequent whitespace (including the newline)
+ up to the next non-whitespace character (this allows the continuation
+ of long string constants across lines). Un-escaped newline and
+ return characters are illegal inside string literals.
+
+ The constructs "\0o", "\0oo", and "\ooo" (where o represents any
+ octal digit) may be used to represent any non-NUL ASCII characters
+ with their corresponding octal values (thus, "\012" is the same as
+ "\n", "\101" is "A", and "\377" is the ASCII character 255 decimal).
+ However, the NUL character cannot be encoded in this manner; "\0",
+ "\00", and "\000" are converted to the strings "0", "00", and "000"
+ respectively. Similarly, all other escaped characters have the
+ leading backslash removed (e.g., "\a" becomes "a", and "\\" becomes
+ "\"). The following four strings are equivalent:
+
+ "this string contains a newline\n followed by one space."
+
+ "this string contains a newline\n \
+ followed by one space."
+
+ "this str\
+ ing contains a \
+ newline\n followed by one space."
+
+ "this string contains a newline\012\040followed by one space."
+
+4.3.2 String Expressions
+
+ In general, anywhere a quoted string literal is allowed, a `string
+ expression' can be used. A string expression constructs a string
+ from string constants, dereferenced attributes (described in Section
+ 4.4), and a string concatenation operator. String expressions may be
+ parenthesized.
+
+ <StrEx> ::= <StrEx> "." <StrEx> /* String concatenation */
+ | <StringLiteral> /* Quoted string */
+ | "(" <StrEx> ")"
+ | <DerefAttribute> /* See Section 4.4 */
+ | "$" <StrEx> /* See Section 4.4 */
+
+ The "$" operator has higher precedence than the "." operator.
+
+4.4 Dereferenced Attributes
+
+ Action attributes provide the primary mechanism for applications to
+ pass information to assertions. Attribute names are strings from a
+ limited character set (<AttributeID> as defined in Section 3), and
+ attribute values are represented internally as strings. An attribute
+ is dereferenced simply by using its name. In general, KeyNote allows
+ the use of an attribute anywhere a string literal is permitted.
+
+ Attributes are dereferenced as strings by default. When required,
+ dereferenced attributes can be converted to integers or floating
+ point numbers with the type conversion operators "@" and "&". Thus,
+ an attribute named "foo" having the value "1.2" may be interpreted as
+ the string "1.2" (foo), the integer value 1 (@foo), or the floating
+ point value 1.2 (&foo).
+
+ Attributes converted to integer and floating point numbers are
+ represented according to the ANSI C `long' and `float' types,
+ respectively.
+
+ Any uninitialized attribute has the empty-string value when
+ dereferenced as a string and the value zero when dereferenced as an
+ integer or float.
+
+ Attribute names may be given literally or calculated from string
+ expressions and may be recursively dereferenced. In the simplest
+ case, an attribute is dereferenced simply by using its name outside
+ of quotes; e.g., the string value of the attribute named "foo" is by
+ reference to `foo' (outside of quotes). The "$<StrEx>" construct
+ dereferences the attribute named in the string expression <StrEx>.
+ For example, if the attribute named "foo" contains the string "bar",
+ the attribute named "bar" contains the string "xyz", and the
+ attribute "xyz" contains the string "qua", the following string
+ comparisons are all true:
+
+ foo == "bar"
+ $("foo") == "bar"
+ $foo == "xyz"
+ $(foo) == "xyz"
+ $$foo == "qua"
+
+ If <StrEx> evaluates to an invalid or uninitialized attribute name,
+ its value is considered to be the empty string (or zero if used as a
+ numeric).
+
+ The <DerefAttribute> token is defined as:
+
+ <DerefAttribute> ::= <AttributeID>
+
+4.5 Principal Identifiers
+
+ Principals are represented as ASCII strings called `Principal
+ Identifiers.' Principal Identifiers may be arbitrary labels whose
+ structure is not interpreted by the KeyNote system or they may encode
+ cryptographic keys that are used by KeyNote for credential signature
+ verification.
+
+ <PrincipalIdentifier> ::= <OpaqueID>
+ | <KeyID>
+
+4.5.1 Opaque Principal Identifiers
+
+ Principal Identifiers that are used by KeyNote only as labels are
+ said to be `opaque.' Opaque identifiers are encoded in assertions as
+ strings (see Section 4.3):
+
+ <OpaqueID> ::= <StrEx>
+
+ Opaque identifier strings should not contain the ":" character.
+
+4.5.2 Cryptographic Principal Identifiers
+
+ Principal Identifiers that are used by KeyNote as keys, e.g., to
+ verify credential signatures, are said to be `cryptographic.'
+ Cryptographic identifiers are also lexically encoded as strings:
+
+ <KeyID> ::= <StrEx>
+
+ Unlike Opaque Identifiers, however, Cryptographic Identifier strings
+ have a special form. To be interpreted by KeyNote (for signature
+ verification), an identifier string should be of the form:
+
+ ALGORITHM:ENCODEDBITS
+
+ "ALGORITHM" is an ASCII substring that describes the algorithms to be
+ used in interpreting the key's bits. The ALGORITHM identifies the
+ major cryptographic algorithm (e.g., RSA [RSA78], DSA [DSA94], etc.),
+ structured format (e.g., PKCS1 [PKCS1]), and key bit encoding (e.g.,
+ HEX or BASE64). By convention, the ALGORITHM substring starts with
+ an alphabetic character and can contain letters, digits, underscores,
+ or dashes (i.e., it should match the regular expression "[a-zA-Z][a-
+ zA-Z0-9_-]*"). The IANA (or some other appropriate authority) will
+ provide a registry of reserved algorithm identifiers.
+
+ "ENCODEDBITS" is a substring of characters representing the key's
+ bits, the encoding and format of which depends on the ALGORITHM. By
+ convention, hexadecimal encoded keys use lower-case ASCII characters.
+
+ Cryptographic Principal Identifiers are converted to a normalized
+ canonical form for the purposes of any internal comparisons between
+ them; see Section 5.2.
+
+ Note that the keys used in examples throughout this document are
+ fictitious and generally much shorter than would be required for
+ security in practice.
+
+4.6 KeyNote Fields
+
+4.6.1 The KeyNote-Version Field
+
+ The KeyNote-Version field identifies the version of the KeyNote
+ assertion language under which the assertion was written. The
+ KeyNote-Version field is of the form
+
+ <VersionField> ::= "KeyNote-Version:" <VersionString>
+ <VersionString> ::= <StringLiteral>
+ | <IntegerLiteral>
+
+ where <VersionString> is an ASCII-encoded string. Assertions in
+ production versions of KeyNote use decimal digits in the version
+ representing the version number of the KeyNote language under which
+ they are to be interpreted. Assertions written to conform with this
+ document should be identified with the version string "2" (or the
+ integer 2). The KeyNote-Version field, if included, should appear
+ first.
+
+4.6.2 The Local-Constants Field
+
+ This field adds or overrides action attributes in the current
+ assertion only. This mechanism allows the use of short names for
+ (frequently lengthy) cryptographic principal identifiers, especially
+ to make the Licensees field more readable. The Local-Constants field
+ is of the form:
+
+ <LocalConstantsField> ::= "Local-Constants:" <Assignments>
+ <Assignments> ::= /* can be empty */
+ | <AttributeID> "=" <StringLiteral>
+ | <Assignments> <Assignments>
+
+ <AttributeID> is an attribute name from the action attribute
+ namespace as defined in Section 3. The name is available for use as
+ an attribute in any subsequent field. If the Local-Constants field
+ defines more than one identifier, it can occupy more than one line
+ and be indented. <StringLiteral> is a string literal as described in
+ Section 4.3. Attributes defined in the Local-Constants field
+ override any attributes with the same name passed in with the action
+ attribute set.
+
+ An attribute may be initialized at most once in the Local-Constants
+ field. If an attribute is initialized more than once in an
+ assertion, the entire assertion is considered invalid and is not
+ considered by the KeyNote compliance checker in evaluating queries.
+
+4.6.3 The Authorizer Field
+
+ The Authorizer identifies the Principal issuing the assertion. This
+ field is of the form
+
+ <AuthField> ::= "Authorizer:" <AuthID>
+ <AuthID> ::= <PrincipalIdentifier>
+ | <DerefAttribute>
+
+ The Principal Identifier may be given directly or by reference to the
+ attribute namespace (as defined in Section 4.4).
+
+4.6.4 The Licensees Field
+
+ The Licensees field identifies the principals authorized by the
+ assertion. More than one principal can be authorized, and
+ authorization can be distributed across several principals through
+ the use of `and' and threshold constructs. This field is of the form
+
+ <LicenseesField> ::= "Licensees:" <LicenseesExpr>
+
+ <LicenseesExpr> ::= /* can be empty */
+ | <PrincExpr>
+
+ <PrincExpr> ::= "(" <PrincExpr> ")"
+ | <PrincExpr> "&&" <PrincExpr>
+ | <PrincExpr> "||" <PrincExpr>
+ | <K>"-of(" <PrincList> ")" /* Threshold */
+ | <PrincipalIdentifier>
+ | <DerefAttribute>
+
+ <PrincList> ::= <PrincipalIdentifier>
+ | <DerefAttribute>
+ | <PrincList> "," <PrincList>
+
+ <K> ::= [1-9][0-9]*
+
+ The "&&" operator has higher precedence than the "||" operator. <K>
+ is an ASCII-encoded positive decimal integer. If a <PrincList>
+ contains fewer than <K> principals, the entire assertion is omitted
+ from processing.
+
+4.6.5 The Conditions Field
+
+ This field gives the `conditions' under which the Authorizer trusts
+ the Licensees to perform an action. `Conditions' are predicates that
+ operate on the action attribute set. The Conditions field is of the
+ form:
+
+ <ConditionsField> ::= "Conditions:" <ConditionsProgram>
+
+ <ConditionsProgram> ::= /* Can be empty */
+ | <Clause> ";" <ConditionsProgram>
+
+ <Clause> ::= <Test> "->" "{" <ConditionsProgram> "}"
+ | <Test> "->" <Value>
+ | <Test>
+
+ <Value> ::= <StrEx>
+
+ <Test> ::= <RelExpr>
+
+ <RelExpr> ::= "(" <RelExpr> ")" /* Parentheses */
+ | <RelExpr> "&&" <RelExpr> /* Logical AND */
+ | <RelExpr> "||" <RelExpr> /* Logical OR */
+ | "!" <RelExpr> /* Logical NOT */
+ | <IntRelExpr>
+ | <FloatRelExpr>
+ | <StringRelExpr>
+ | "true" /* case insensitive */
+ | "false" /* case insensitive */
+
+ <IntRelExpr> ::= <IntEx> "==" <IntEx>
+ | <IntEx> "!=" <IntEx>
+ | <IntEx> "<" <IntEx>
+ | <IntEx> ">" <IntEx>
+ | <IntEx> "<=" <IntEx>
+ | <IntEx> ">=" <IntEx>
+
+ <FloatRelExpr> ::= <FloatEx> "<" <FloatEx>
+ | <FloatEx> ">" <FloatEx>
+ | <FloatEx> "<=" <FloatEx>
+ | <FloatEx> ">=" <FloatEx>
+
+ <StringRelExpr> ::= <StrEx> "==" <StrEx> /* String equality */
+ | <StrEx> "!=" <StrEx> /* String inequality */
+ | <StrEx> "<" <StrEx> /* Alphanum. comparisons */
+ | <StrEx> ">" <StrEx>
+ | <StrEx> "<=" <StrEx>
+ | <StrEx> ">=" <StrEx>
+ | <StrEx> "~=" <RegExpr> /* Regular expr. matching */
+
+ <IntEx> ::= <IntEx> "+" <IntEx> /* Integer */
+ | <IntEx> "-" <IntEx>
+ | <IntEx> "*" <IntEx>
+ | <IntEx> "/" <IntEx>
+ | <IntEx> "%" <IntEx>
+ | <IntEx> "^" <IntEx> /* Exponentiation */
+ | "-" <IntEx>
+ | "(" <IntEx> ")"
+ | <IntegerLiteral>
+ | "@" <StrEx>
+
+ <FloatEx> ::= <FloatEx> "+" <FloatEx> /* Floating point */
+ | <FloatEx> "-" <FloatEx>
+ | <FloatEx> "*" <FloatEx>
+ | <FloatEx> "/" <FloatEx>
+ | <FloatEx> "^" <FloatEx> /* Exponentiation */
+ | "-" <FloatEx>
+ | "(" <FloatEx> ")"
+ | <FloatLiteral>
+ | "&" <StrEx>
+
+ <IntegerLiteral> ::= [0-9]+
+ <FloatLiteral> ::= [0-9]+\.[0-9]+
+
+ <StringLiteral> is a quoted string as defined in Section 4.3
+ <AttributeID> is defined in Section 3.
+
+ The operation precedence classes are (from highest to lowest):
+
+ { (, ) }
+ {unary -, @, &, $}
+ {^}
+ {*, /, %}
+ {+, -, .}
+
+ Operators in the same precedence class are evaluated left-to-right.
+
+ The keywords "true" and "false" are not reserved; they can be used as
+ attribute or principal identifier names (although this practice makes
+ assertions difficult to understand and is discouraged).
+
+ <RegExpr> is a standard regular expression, conforming to the POSIX
+ 1003.2 regular expression syntax and semantics.
+
+ Any string expression (or attribute) containing the ASCII
+ representation of a numeric value can be converted to an integer or
+ float with the use of the "@" and "&" operators, respectively. Any
+ fractional component of an attribute value dereferenced as an integer
+ is rounded down. If an attribute dereferenced as a number cannot be
+ properly converted (e.g., it contains invalid characters or is empty)
+ its value is considered to be zero.
+
+4.6.6 The Comment Field
+
+ The Comment field allows assertions to be annotated with information
+ describing their purpose. It is of the form
+
+ <CommentField> ::= "Comment:" <text>
+
+ No interpretation of the contents of this field is performed by
+ KeyNote. Note that this is one of two mechanisms for including
+ comments in KeyNote assertions; comments can also be inserted
+ anywhere in an assertion's body by preceeding them with the "#"
+ character.
+
+4.6.7 The Signature Field
+
+ The Signature field identifies a signed assertions and gives the
+ encoded digital signature of the principal identified in the
+ Authorizer field. The Signature field is of the form:
+
+ <SignatureField> ::= "Signature:" <Signature>
+
+ <Signature> ::= <StrEx>
+
+ The <Signature> string should be of the form:
+
+ ALGORITHM:ENCODEDBITS
+
+ The formats of the "ALGORITHM" and "ENCODEDBITS" substrings are as
+ described for Cryptographic Principal Identifiers in Section 4.4.2
+ The algorithm name should be the same as that of the principal
+ appearing in the Authorizer field. The IANA (or some other suitable
+ authority) will provide a registry of reserved names. It is not
+ necessary that the encodings of the signature and the authorizer key
+ be the same.
+
+ If the signature field is included, the principal named in the
+ Authorizer field must be a Cryptographic Principal Indentifier, the
+ algorithm must be known to the KeyNote implementation, and the
+ signature must be correct for the assertion body and authorizer key.
+
+ The signature is computed over the assertion text, beginning with the
+ first field (including the field identifier string), up to (but not
+ including) the Signature field identifier. The newline preceeding
+ the signature field identifier is the last character included in
+ signature calculation. The signature is always the last field in a
+ KeyNote assertion. Text following this field is not considered part
+ of the assertion.
+
+ The algorithms for computing and verifying signatures must be
+ configured into each KeyNote implementation and are defined and
+ documented separately.
+
+ Note that all signatures used in examples in this document are
+ fictitious and generally much shorter than would be required for
+ security in practice.
+
+
+5. Query Evaluation Semantics
+
+ The KeyNote compliance checker finds and returns the Policy
+ Compliance Value of queries, as defined in Section 5.3, below.
+
+5.1 Query Parameters
+
+ A KeyNote query has four parameters:
+
+ * The identifier of the principal(s) requesting the action.
+
+ * The action attribute set describing the action.
+
+ * The set of compliance values of interest to the application,
+ ordered from _MIN_TRUST to _MAX_TRUST
+
+ * The policy and credential assertions that should be included
+ in the evaluation.
+
+ The mechanism for passing these parameters to the KeyNote evaluator
+ is application dependent. In particular, an evaluator might provide
+ for some parameters to be passed explicitly, while others are looked
+ up externally (e.g., credentials might be looked up in a network-
+ based distribution system), while still others might be requested
+ from the application as needed by the evaluator, through a `callback'
+ mechanism (e.g., for attribute values that represent values from
+ among a very large namespace).
+
+5.1.1 Action Requester
+
+ At least one Principal must be identified in each query as the
+ `requester' of the action. Actions may be requested by several
+ principals, each considered to have individually requested it. This
+ allows policies that require multiple authorizations, e.g., `two
+ person control.' The set of authorizing principals is made available
+ in the special attribute "_ACTION_AUTHORIZERS"; if several principals
+ are authorizers, their identifiers are separated with commas.
+
+5.1.2 Ordered Compliance Value Set
+
+ The set of compliance values of interest to an application (and their
+ relative ranking to one another) is determined by the invoking
+ application and passed to the KeyNote evaluator as a parameter of the
+ query. In many applications, this will be Boolean, e.g., the ordered
+ sets {FALSE, TRUE} or {REJECT, APPROVE}. Other applications may
+ require a range of possible values, e.g., {No_Access, Limited_Access,
+ Full_Access}. Note that applications should include in this set only
+ compliance values names that are actually returned by the assertions.
+
+ The lowest-order and highest-order compliance value strings given in
+ the query are available in the special attributes named "_MIN_TRUST"
+ and "_MAX_TRUST", respectively. The complete set of query compliance
+ values is made available in ascending order (from _MIN_TRUST to
+ _MAX_TRUST) in the special attribute named "_VALUES". Values are
+ separated with commas; applications that use assertions that make use
+ of the _VALUES attribute should therefore avoid the use of compliance
+ value strings that themselves contain commas.
+
+5.2 Principal Identifier Normalization
+
+ Principal identifier comparisons among Cryptographic Principal
+ Identifiers (that represent keys) in the Authorizer and Licensees
+ fields or in an action's direct authorizers are performed after
+ normalizing them by conversion to a canonical form.
+
+ Every cryptographic algorithm used in KeyNote defines a method for
+ converting keys to their canonical form and that specifies how the
+ comparison for equality of two keys is performed. If the algorithm
+ named in the identifier is unknown to KeyNote, the identifier is
+ treated as opaque.
+
+ Opaque identifiers are compared as case-sensitive strings.
+
+ Notice that use of opaque identifiers in the Authorizer field
+ requires that the assertion's integrity be locally trusted (since it
+ cannot be cryptographically verified by the compliance checker).
+
+5.3 Policy Compliance Value Calculation
+
+ The Policy Compliance Value of a query is the Principal Compliance
+ Value of the principal named "POLICY". This value is defined as
+ follows:
+
+5.3.1 Principal Compliance Value
+
+ The Compliance Value of a principal <X> is the highest order
+ (maximum) of:
+
+ - the Direct Authorization Value of principal <X>; and
+
+ - the Assertion Compliance Values of all assertions identifying
+ <X> in the Authorizer field.
+
+5.3.2 Direct Authorization Value
+
+ The Direct Authorization Value of a principal <X> is _MAX_TRUST if
+ <X> is listed in the query as an authorizer of the action.
+ Otherwise, the Direct Authorization Value of <X> is _MIN_TRUST.
+
+5.3.3 Assertion Compliance Value
+
+ The Assertion Compliance Value of an assertion is the lowest order
+ (minimum) of the assertion's Conditions Compliance Value and its
+ Licensee Compliance Value.
+
+5.3.4 Conditions Compliance Value
+
+ The Conditions Compliance Value of an assertion is the highest- order
+ (maximum) value among all successful clauses listed in the conditions
+ section.
+
+ If no clause's test succeeds or the Conditions field is empty, an
+ assertion's conditions compliance value is considered to be the
+ _MIN_TRUST value, as defined Section 5.1.
+
+ If an assertion's Conditions field is missing entirely, its
+ conditions compliance value is considered to be the _MAX_TRUST value,
+ as defined in Section 5.1.
+
+ The set of successful test clause values is calculated as follows:
+
+ Recall from the grammar of section 4.6.5 that each clause in the
+ conditions section has two logical parts: a `test' and an optional
+ `value,' which, if present, is separated from the test with the "->"
+ token. The test subclause is a predicate that either succeeds
+ (evaluates to logical `true') or fails (evaluates to logical
+ `false'). The value subclause is a string expression that evaluates
+ to one value from the ordered set of compliance values given with the
+ query. If the value subclause is missing, it is considered to be
+ _MAX_TRUST. That is, the clause
+
+ foo=="bar";
+
+ is equivalent to
+
+ foo=="bar" -> _MAX_TRUST;
+
+ If the value component of a clause is present, in the simplest case
+ it contains a string expression representing a possible compliance
+ value. For example, consider an assertion with the following
+ Conditions field:
+
+ Conditions:
+ @user_id == 0 -> "full_access"; # clause (1)
+ @user_id < 1000 -> "user_access"; # clause (2)
+ @user_id < 10000 -> "guest_access"; # clause (3)
+ user_name == "root" -> "full_access"; # clause (4)
+
+ Here, if the value of the "user_id" attribute is "1073" and the
+ "user_name" attribute is "root", the possible compliance value set
+ would contain the values "guest_access" (by clause (3)) and
+ "full_access" (by clause (4)). If the ordered set of compliance
+ values given in the query (in ascending order) is {"no_access",
+ "guest_access", "user_access", "full_access"}, the conditions
+ compliance value of the assertion would be "full_access" (because
+ "full_access" has a higher-order value than "guest_access"). If the
+ "user_id" attribute had the value "19283" and the "user_name"
+ attribute had the value "nobody", no clause would succeed and the
+ conditions compliance value would be "no_access", which is the
+ lowest-order possible value (_MIN_TRUST).
+
+ If a clause lists an explicit value, its value string must be named
+ in the query ordered compliance value set. Values not named in the
+ query compliance value set are considered equivalent to _MIN_TRUST.
+
+ The value component of a clause can also contain recursively-nested
+ clauses. Recursively-nested clauses are evaluated only if their
+ parent test is true. That is,
+
+ a=="b" -> { b=="c" -> "value1";
+ d=="e" -> "value2";
+ true -> "value3"; } ;
+
+ is equivalent to
+
+ (a=="b") && (b=="c") -> "value1";
+ (a=="b") && (d=="e") -> "value2";
+ (a=="b") -> "value3";
+
+ String comparisons are case-sensitive.
+
+ A regular expression comparison ("~=") is considered true if the
+ left-hand-side string expression matches the right-hand-side regular
+ expression. If the POSIX regular expression group matching scheme is
+ used, the number of groups matched is placed in the temporary meta-
+ attribute "_0" (dereferenced as _0), and each match is placed in
+ sequence in the temporary attributes (_1, _2, ..., _N). These match
+ attributes values are valid only within subsequent references made
+ within the same clause. Regular expression evaluation is case-
+ sensitive.
+
+ A runtime error occurring in the evaluation of a test, such as
+ division by zero or an invalid regular expression, causes the test to
+ be considered false. For example:
+
+ foo == "bar" -> {
+ @a == 1/0 -> "oneval"; # subclause 1
+ @a == 2 -> "anotherval"; # subclause 2
+ };
+
+ Here, subclause 1 triggers a runtime error. Subclause 1 is therefore
+ false (and has the value _MIN_TRUST). Subclause 2, however, would be
+ evaluated normally.
+
+ An invalid <RegExpr> is considered a runtime error and causes the
+ test in which it occurs to be considered false.
+
+5.3.5 Licensee Compliance Value
+
+ The Licensee Compliance Value of an assertion is calculated by
+ evaluating the expression in the Licensees field, based on the
+ Principal Compliance Value of the principals named there.
+
+ If an assertion's Licensees field is empty, its Licensee Compliance
+ Value is considered to be _MIN_TRUST. If an assertion's Licensees
+ field is missing altogether, its Licensee Compliance Value is
+ considered to be _MAX_TRUST.
+
+ For each principal named in the Licensees field, its Principal
+ Compliance Value is substituted for its name. If no Principal
+ Compliance Value can be found for some named principal, its name is
+ substituted with the _MIN_TRUST value.
+
+ The licensees expression (as defined in Section 4.6.4) is evaluated
+ as follows:
+
+ * A "(...)" expression has the value of the enclosed subexpression.
+
+ * A "&&" expression has the lower-order (minimum) of its two
+ subexpression values.
+
+ * A "||" expression has the higher-order (maximum) of its two
+ subexpression values.
+
+ * A "<K>-of(<List>)" expression has the K-th highest order
+ compliance value listed in <list>. Values that appear multiple
+ times are counted with multiplicity. For example, if K = 3 and
+ the orders of the listed compliance values are (0, 1, 2, 2, 3),
+ the value of the expression is the compliance value of order 2.
+
+ For example, consider the following Licensees field:
+
+ Licensees: ("alice" && "bob") || "eve"
+
+ If the Principal Compliance Value is "yes" for principal "alice",
+ "no" for principal "bob", and "no" for principal "eve", and "yes" is
+ higher order than "no" in the query's Compliance Value Set, then the
+ resulting Licensee Compliance Value is "no".
+
+ Observe that if there are exactly two possible compliance values
+ (e.g., "false" and "true"), the rules of Licensee Compliance Value
+ resolution reduce exactly to standard Boolean logic.
+
+5.4 Assertion Management
+
+ Assertions may be either signed or unsigned. Only signed assertions
+ should be used as credentials or transmitted or stored on untrusted
+ media. Unsigned assertions should be used only to specify policy and
+ for assertions whose integrity has already been verified as
+ conforming to local policy by some mechanism external to the KeyNote
+ system itself (e.g., X.509 certificates converted to KeyNote
+ assertions by a trusted conversion program).
+
+ Implementations that permit signed credentials to be verified by the
+ KeyNote compliance checker generally provide two `channels' through
+ which applications can make assertions available. Unsigned, locally-
+ trusted assertions are provided over a `trusted' interface, while
+ signed credentials are provided over an `untrusted' interface. The
+ KeyNote compliance checker verifies correct signatures for all
+ assertions submitted over the untrusted interface. The integrity of
+ KeyNote evaluation requires that only assertions trusted as
+ reflecting local policy are submitted to KeyNote via the trusted
+ interface.
+
+ Note that applications that use KeyNote exclusively as a local policy
+ specification mechanism need use only trusted assertions. Other
+ applications might need only a small number of infrequently changed
+ trusted assertions to `bootstrap' a policy whose details are
+ specified in signed credentials issued by others and submitted over
+ the untrusted interface.
+
+5.5 Implementation Issues
+
+ Informally, the semantics of KeyNote evaluation can be thought of as
+ involving the construction a directed graph of KeyNote assertions
+ rooted at a POLICY assertion that connects with at least one of the
+ principals that requested the action.
+
+ Delegation of some authorization from principal <A> to a set of
+ principals <B> is expressed as an assertion with principal <A> given
+ in the Authorizer field, principal set <B> given in the Licensees
+ field, and the authorization to be delegated encoded in the
+ Conditions field. How the expression digraph is constructed is
+ implementation-dependent and implementations may use different
+ algorithms for optimizing the graph's construction. Some
+ implementations might use a `bottom up' traversal starting at the
+ principals that requested the action, others might follow a `top
+ down' approach starting at the POLICY assertions, and still others
+ might employ other heuristics entirely.
+
+
+ 6. Examples
+
+ In this section, we give examples of KeyNote assertions that might be
+ used in hypothetical applications. These examples are intended
+ primarily to illustrate features of KeyNote assertion syntax and
+ semantics, and do not necessarily represent the best way to integrate
+ KeyNote into applications.
+
+ In the interest of readability, we use much shorter keys than would
+ ordinarily be used in practice. Note that the Signature fields in
+ these examples do not represent the result of any real signature
+ calculation.
+
+ 1. TRADITIONAL CA / EMAIL
+
+ A. A policy unconditionally authorizing RSA key abc123 for all
+ actions. This essentially defers the ability to specify
+ policy to the holder of the secret key corresponding to
+ abc123:
+
+ Authorizer: "POLICY"
+ Licensees: "RSA:abc123"
+
+ B. A credential assertion in which RSA Key abc123 trusts either
+ RSA key 4401ff92 (called `Alice') or DSA key d1234f (called
+ `Bob') to perform actions in which the "app_domain" is
+ "RFC822-EMAIL", where the "address" matches the regular
+ expression "^.*@keynote\.research\.att\.com$". In other
+ words, abc123 trusts Alice and Bob as certification
+ authorities for the keynote.research.att.com domain.
+
+ KeyNote-Version: 2
+ Local-Constants: Alice="DSA:4401ff92" # Alice's key
+ Bob="RSA:d1234f" # Bob's key
+ Authorizer: "RSA:abc123"
+ Licensees: Alice || Bob
+ Conditions: (app_domain == "RFC822-EMAIL") &&
+ (address ~= # only applies to one domain
+ "^.*@keynote\\.research\\.att\\.com$");
+ Signature: "RSA-SHA1:213354f9"
+
+ C. A certificate credential for a specific user whose email
+ address is mab@keynote.research.att.com and whose name, if
+ present, must be "M. Blaze". The credential was issued by the
+ `Alice' authority (whose key is certified in Example B
+ above):
+
+ KeyNote-Version: 2
+ Authorizer: "DSA:4401ff92" # the Alice CA
+ Licensees: "DSA:12340987" # mab's key
+ Conditions: ((app_domain == "RFC822-EMAIL") &&
+ (name == "M. Blaze" || name == "") &&
+ (address == "mab@keynote.research.att.com"));
+ Signature: "DSA-SHA1:ab23487"
+
+ D. Another certificate credential for a specific user, also
+ issued by the `Alice' authority. This example allows three
+ different keys to sign as jf@keynote.research.att.com (each
+ for a different cryptographic algorithm). This is, in
+ effect, three credentials in one:
+
+ KeyNote-Version: "2"
+ Authorizer: "DSA:4401ff92" # the Alice CA
+ Licensees: "DSA:abc991" || # jf's DSA key
+ "RSA:cde773" || # jf's RSA key
+ "BFIK:fd091a" # jf's BFIK key
+ Conditions: ((app_domain == "RFC822-EMAIL") &&
+ (name == "J. Feigenbaum" || name == "") &&
+ (address == "jf@keynote.research.att.com"));
+ Signature: "DSA-SHA1:8912aa"
+
+ Observe that under policy A and credentials B, C and D, the
+ following action attribute sets are accepted (they return
+ _MAX_TRUST):
+
+ _ACTION_AUTHORIZERS = "dsa:12340987"
+ app_domain = "RFC822-EMAIL"
+ address = "mab@keynote.research.att.com"
+ and
+ _ACTION_AUTHORIZERS = "dsa:12340987"
+ app_domain = "RFC822-EMAIL"
+ address = "mab@keynote.research.att.com"
+ name = "M. Blaze"
+
+ while the following are not accepted (they return
+ _MIN_TRUST):
+
+ _ACTION_AUTHORIZERS = "dsa:12340987"
+ app_domain = "RFC822-EMAIL"
+ address = "angelos@dsl.cis.upenn.edu"
+ and
+ _ACTION_AUTHORIZERS = "dsa:abc991"
+ app_domain = "RFC822-EMAIL"
+ address = "mab@keynote.research.att.com"
+ name = "M. Blaze"
+ and
+ _ACTION_AUTHORIZERS = "dsa:12340987"
+ app_domain = "RFC822-EMAIL"
+ address = "mab@keynote.research.att.com"
+ name = "J. Feigenbaum"
+
+ 2. WORKFLOW/ELECTRONIC COMMERCE
+
+ E. A policy that delegates authority for the "SPEND" application
+ domain to RSA key dab212 when the amount given in the
+ "dollars" attribute is less than 10000.
+
+ Authorizer: "POLICY"
+ Licensees: "RSA:dab212" # the CFO's key
+ Conditions: (app_domain=="SPEND") && (@dollars < 10000);
+
+ F. RSA key dab212 delegates authorization to any two signers,
+ from a list, one of which must be DSA key feed1234 in the
+ "SPEND" application when @dollars < 7500. If the amount in
+ @dollars is 2500 or greater, the request is approved but
+ logged.
+
+ KeyNote-Version: 2
+ Comment: This credential specifies a spending policy
+ Authorizer: "RSA:dab212" # the CFO
+ Licensees: "DSA:feed1234" && # The vice president
+ ("RSA:abc123" || # middle manager #1
+ "DSA:bcd987" || # middle manager #2
+ "DSA:cde333" || # middle manager #3
+ "DSA:def975" || # middle manager #4
+ "DSA:978add") # middle manager #5
+ Conditions: (app_domain=="SPEND") # note nested clauses
+ -> { (@(dollars) < 2500)
+ -> _MAX_TRUST;
+ (@(dollars) < 7500)
+ -> "ApproveAndLog";
+ };
+ Signature: "RSA-SHA1:9867a1"
+
+ G. According to this policy, any two signers from the list of
+ managers will do if @(dollars) < 1000:
+
+ KeyNote-Version: 2
+ Authorizer: "POLICY"
+ Licensees: 2-of("DSA:feed1234", # The VP
+ "RSA:abc123", # Middle management clones
+ "DSA:bcd987",
+ "DSA:cde333",
+ "DSA:def975",
+ "DSA:978add")
+ Conditions: (app_domain=="SPEND") &&
+ (@(dollars) < 1000);
+
+ H. A credential from dab212 with a similar policy, but only one
+ signer is required if @(dollars) < 500. A log entry is made if
+ the amount is at least 100.
+
+ KeyNote-Version: 2
+ Comment: This one credential is equivalent to six separate
+ credentials, one for each VP and middle manager.
+ Individually, they can spend up to $500, but if
+ it's $100 or more, we log it.
+ Authorizer: "RSA:dab212" # From the CFO
+ Licensees: "DSA:feed1234" || # The VP
+ "RSA:abc123" || # The middle management clones
+ "DSA:bcd987" ||
+ "DSA:cde333" ||
+ "DSA:def975" ||
+ "DSA:978add"
+ Conditions: (app_domain="SPEND") # nested clauses
+ -> { (@(dollars) < 100) -> _MAX_TRUST;
+ (@(dollars) < 500) -> "ApproveAndLog";
+ };
+ Signature: "RSA-SHA1:186123"
+
+ Assume a query in which the ordered set of Compliance Values is
+ {"Reject", "ApproveAndLog", "Approve"}. Under policies E and G,
+ and credentials F and H, the Policy Compliance Value is
+ "Approve" (_MAX_TRUST) when:
+
+ _ACTION_AUTHORIZERS = "DSA:978add"
+ app_domain = "SPEND"
+ dollars = "45"
+ unmentioned_attribute = "whatever"
+ and
+ _ACTION_AUTHORIZERS = "RSA:abc123,DSA:cde333"
+ app_domain = "SPEND"
+ dollars = "550"
+
+ The following return "ApproveAndLog":
+
+ _ACTION_AUTHORIZERS = "DSA:feed1234,DSA:cde333"
+ app_domain = "SPEND"
+ dollars = "5500"
+ and
+ _ACTION_AUTHORIZERS = "DSA:cde333"
+ app_domain = "SPEND"
+ dollars = "150"
+
+ However, the following return "Reject" (_MIN_TRUST):
+
+ _ACTION_AUTHORIZERS = "DSA:def975"
+ app_domain = "SPEND"
+ dollars = "550"
+ and
+ _ACTION_AUTHORIZERS = "DSA:cde333,DSA:978add"
+ app_domain = "SPEND"
+ dollars = "5500"
+
+
+7. Trust-Management Architecture
+
+ KeyNote provides a simple mechanism for describing security policy
+ and representing credentials. It differs from traditional
+ certification systems in that the security model is based on binding
+ keys to predicates that describe what the key is authorized by policy
+ to do, rather than on resolving names. The infrastructure and
+ architecture to support a KeyNote system is therefore rather
+ different from that required for a name-based certification scheme.
+ The KeyNote trust-management architecture is based on that of
+ PolicyMaker [BFL96,BFS98].
+
+ It is important to understand the separation between the
+ responsibilities of the KeyNote system and those of the application
+ and other support infrastructure. A KeyNote compliance checker will
+ determine, based on policy and credential assertions, whether a
+ proposed action is permitted according to policy. The usefulness of
+ KeyNote output as a policy enforcement mechanism depends on a number
+ of factors:
+
+ * The action attributes and the assignment of their values must
+ reflect accurately the security requirements of the application.
+ Identifying the attributes to include in the action attribute set
+ is perhaps the most important task in integrating KeyNote into
+ new applications.
+
+ * The policy of the application must be correct and well-formed.
+ In particular, trust must be deferred only to principals that
+ should, in fact, be trusted by the application.
+
+ * The application itself must be trustworthy. KeyNote does not
+ directly enforce policy; it only provides advice to the
+ applications that call it. In other words, KeyNote assumes that
+ the application itself is trusted and that the policy assertions
+ it specifies are correct. Nothing prevents an application from
+ submitting misleading or incorrect assertions to KeyNote or from
+ ignoring KeyNote altogether.
+
+ It is also up to the application (or some service outside KeyNote) to
+ select the appropriate credentials and policy assertions with which
+ to run a particular query. Note, however, that even if inappropriate
+ credentials are provided to KeyNote, this cannot result in the
+ approval of an illegal action (as long as the policy assertions are
+ correct and the the action attribute set itself is correctly passed
+ to KeyNote).
+
+ KeyNote is monotonic; adding an assertion to a query can never result
+ in a query's having a lower compliance value that it would have had
+ without the assertion. Omitting credentials may, of course, result
+ in legal actions being disallowed. Selecting appropriate credentials
+ (e.g., from a distributed database or `key server') is outside the
+ scope of the KeyNote language and may properly be handled by a remote
+ client making a request, by the local application receiving the
+ request, or by a network-based service, depending on the application.
+
+ In addition, KeyNote does not itself provide credential revocation
+ services, although credentials can be written to expire after some
+ date by including a date test in the predicate. Applications that
+ require credential revocation can use KeyNote to help specify and
+ implement revocation policies. A future document will address
+ expiration and revocation services in KeyNote.
+
+ Because KeyNote is designed to support a variety of applications,
+ several different application interfaces to a KeyNote implementation
+ are possible. In its simplest form, a KeyNote compliance checker
+ would exist as a stand-alone application, with other applications
+ calling it as needed. KeyNote might also be implemented as a library
+ to which applications are linked. Finally, a KeyNote implementation
+ might run as a local trusted service, with local applications
+ communicating their queries via some interprocess communication
+ mechanism.
+
+
+8. Security Considerations
+
+ Trust management is itself a security service. Bugs in or incorrect
+ use of a KeyNote compliance checker implementation could have
+ security implications for any applications in which it is used.
+
+
+9. Acknowledgments
+
+ We thank Lorrie Faith Cranor (AT&T Labs - Research) and Jonathan M.
+ Smith (University of Pennsylvania) for their suggestions and comments
+ on earlier versions of this.
+
+
+References
+
+ [BFL96] M. Blaze, J. Feigenbaum, J. Lacy. Decentralized Trust
+ Management. Proceedings of the 17th IEEE Symp. on Security
+ and Privacy. pp 164-173. IEEE Computer Society,
+ 1996. Available at
+ <ftp://ftp.research.att.com/dist/mab/policymaker.ps>
+
+ [BFS98] M. Blaze, J. Feigenbaum, M. Strauss. Compliance-Checking in
+ the PolicyMaker Trust-Management System. Proc. 2nd
+ Financial Crypto Conference. Anguila 1998. LNCS #1465, pp
+ 251-265, Springer-Verlag, 1998. Available at
+ <ftp://ftp.research.att.com/dist/mab/pmcomply.ps>
+
+ [Bla99] M. Blaze, J. Feigenbaum, J. Ioannidis, A. Keromytis. The
+ Role of Trust Management in Distributed System Security.
+ Chapter in Secure Internet Programming: Security Issues for
+ Mobile and Distributed Objects (Vitek and Jensen, eds.).
+ Springer-Verlag, 1999. Available at
+ <ftp://ftp.research.att.com/dist/mab/trustmgt.ps>.
+
+ [Cro82] D. H. Crocker. Standard for the Format of ARPA Internet
+ Text Messages. RFC 822. August 1982.
+
+ [DSA94] Digital Signature Standard. FIPS-186. National Institute of
+ Standards, U.S. Department of Commerce. May 1994.
+
+ [PKCS1] PKCS #1: RSA Encryption Standard, Version 1.5. RSA
+ Laboratories. November 1993.
+
+ [RSA78] R. L. Rivest, A. Shamir, L. M. Adleman. A Method for
+ Obtaining Digital Signatures and Public-Key Cryptosystems.
+ Communications of the ACM, v21n2. pp 120-126. February
+ 1978.
+
+Contacts
+
+ Comments about this document should be discussed on the
+ trustmgt@east.isi.edu mailing list. The archive for that list can be
+ found at http://www.cairn.net/trustmgt/.
+
+ Questions about this document can also be directed to the authors as
+ a group at the keynote@research.att.com alias, or to the individual
+ authors at:
+
+ Matt Blaze Joan Feigenbaum John Ioannidis
+ mab@research.att.com jf@research.att.com ji@research.att.com
+
+ AT&T Labs - Research
+ 180 Park Avenue
+ Florham Park, New Jersey 07932-0000
+
+ Angelos D. Keromytis
+ Distributed Systems Lab
+ CIS Department, University of Pennsylvania
+ 200 S. 33rd Street
+ Philadelphia, Pennsylvania 19104-6389
+ Email: angelos@dsl.cis.upenn.edu
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1999). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/libkeynote/environment.c b/lib/libkeynote/environment.c
new file mode 100644
index 00000000000..a8c0fce540d
--- /dev/null
+++ b/lib/libkeynote/environment.c
@@ -0,0 +1,874 @@
+/* $OpenBSD: environment.c,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#ifdef WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "environment.h"
+#include "signature.h"
+
+static int sessioncounter = 0;
+
+/* Globals */
+struct keynote_session *keynote_sessions[SESSIONTABLESIZE];
+struct keynote_session *keynote_current_session;
+int keynote_justrecord = 0;
+int keynote_returnvalue = 0;
+
+/*
+ * Construct the _ACTION_AUTHORIZERS variable value.
+ */
+static char *
+keynote_get_action_authorizers(char *name)
+{
+ struct keylist *kl;
+ int len;
+
+ if (!strcmp(name, KEYNOTE_CALLBACK_CLEANUP) ||
+ !strcmp(name, KEYNOTE_CALLBACK_INITIALIZE))
+ {
+ if (keynote_current_session->ks_authorizers_cache != (char *) NULL)
+ {
+ free(keynote_current_session->ks_authorizers_cache);
+ keynote_current_session->ks_authorizers_cache = (char *) NULL;
+ }
+
+ return "";
+ }
+
+ if (keynote_current_session->ks_authorizers_cache != (char *) NULL)
+ return keynote_current_session->ks_authorizers_cache;
+
+ for (len = 0, kl = keynote_current_session->ks_action_authorizers;
+ kl != (struct keylist *) NULL;
+ kl = kl->key_next)
+ if (kl->key_stringkey != (char *) NULL)
+ len += strlen(kl->key_stringkey) + 1;
+
+ if (len == 0)
+ return "";
+
+ keynote_current_session->ks_authorizers_cache = (char *) calloc(len, sizeof(char));
+ if (keynote_current_session->ks_authorizers_cache == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ for (len = 0, kl = keynote_current_session->ks_action_authorizers;
+ kl != (struct keylist *) NULL;
+ kl = kl->key_next)
+ if (kl->key_stringkey != (char *) NULL)
+ {
+ sprintf(keynote_current_session->ks_authorizers_cache + len, "%s,",
+ kl->key_stringkey);
+ len += strlen(kl->key_stringkey) + 1;
+ }
+
+ keynote_current_session->ks_authorizers_cache[len - 1] = '\0';
+ return keynote_current_session->ks_authorizers_cache;
+}
+
+/*
+ * Construct the _VALUES variable value.
+ */
+static char *
+keynote_get_values(char *name)
+{
+ int i, len;
+
+ if (!strcmp(name, KEYNOTE_CALLBACK_CLEANUP) ||
+ !strcmp(name, KEYNOTE_CALLBACK_INITIALIZE))
+ {
+ if (keynote_current_session->ks_values_cache != (char *) NULL)
+ {
+ free(keynote_current_session->ks_values_cache);
+ keynote_current_session->ks_values_cache = (char *) NULL;
+ }
+
+ return "";
+ }
+
+ if (keynote_current_session->ks_values_cache != (char *) NULL)
+ return keynote_current_session->ks_values_cache;
+
+ for (len = 0, i = 0; i < keynote_current_session->ks_values_num; i++)
+ len += strlen(keynote_current_session->ks_values[i]) + 1;
+
+ keynote_current_session->ks_values_cache = (char *) calloc(len,
+ sizeof(char));
+ if (keynote_current_session->ks_values_cache == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (len == 0)
+ return "";
+
+ for (len = 0, i = 0; i < keynote_current_session->ks_values_num; i++)
+ {
+ sprintf(keynote_current_session->ks_values_cache + len, "%s,",
+ keynote_current_session->ks_values[i]);
+ len += strlen(keynote_current_session->ks_values[i]) + 1;
+ }
+
+ keynote_current_session->ks_values_cache[len - 1] = '\0';
+ return keynote_current_session->ks_values_cache;
+}
+
+/*
+ * Free an environment structure.
+ */
+void
+keynote_free_env(struct environment *en)
+{
+ if (en == (struct environment *) NULL)
+ return;
+
+ if (en->env_name != (char *) NULL)
+ free(en->env_name);
+
+ if (en->env_flags & ENVIRONMENT_FLAG_REGEX)
+ regfree(&(en->env_regex));
+
+ if (!(en->env_flags & ENVIRONMENT_FLAG_FUNC))
+ {
+ if (en->env_value != (char *) NULL)
+ free(en->env_value);
+ }
+ else
+ ((char * (*) (char *))en->env_value)(KEYNOTE_CALLBACK_CLEANUP);
+
+ free(en);
+}
+
+/*
+ * Lookup for variable "name" in the hash table. If hashsize is 1,
+ * then the second argument is actually a pointer to a list. Last
+ * argument specifies case-insensitivity.
+ */
+char *
+keynote_env_lookup(char *name, struct environment **table, u_int hashsize)
+{
+ struct environment *en;
+
+ for (en = table[keynote_stringhash(name, hashsize)];
+ en != (struct environment *) NULL;
+ en = en->env_next)
+ if (((en->env_flags & ENVIRONMENT_FLAG_REGEX) &&
+ (regexec(&(en->env_regex), name, 0, (regmatch_t *) NULL, 0) ==
+ 0)) || (!strcmp(name, en->env_name)))
+ {
+ if ((en->env_flags & ENVIRONMENT_FLAG_FUNC) &&
+ (en->env_value != (char *) NULL))
+ return ((char * (*) (char *)) en->env_value)(name);
+ else
+ return en->env_value;
+ }
+
+ return (char *) NULL;
+}
+
+/*
+ * Delete a variable from hash table. Return RESULT_TRUE if the deletion was
+ * successful, and RESULT_FALSE if the variable was not found.
+ */
+int
+keynote_env_delete(char *name, struct environment **table, u_int hashsize)
+{
+ struct environment *en, *en2;
+ u_int h;
+
+ h = keynote_stringhash(name, hashsize);
+
+ if (table[h] != (struct environment *) NULL)
+ {
+ if (!strcmp(table[h]->env_name, name))
+ {
+ en = table[h];
+ table[h] = en->env_next;
+ keynote_free_env(en);
+ return RESULT_TRUE;
+ }
+ else
+ for (en = table[h];
+ en->env_next != (struct environment *) NULL;
+ en = en->env_next)
+ if (!strcmp(en->env_next->env_name, name))
+ {
+ en2 = en->env_next;
+ en->env_next = en2->env_next;
+ keynote_free_env(en2);
+ return RESULT_TRUE;
+ }
+ }
+
+ return RESULT_FALSE;
+}
+
+/*
+ * Add a new variable in hash table. Return RESULT_TRUE on success,
+ * ERROR_MEMORY on failure. If hashsize is 1, second argument is
+ * actually a pointer to a list. The arguments are duplicated.
+ */
+int
+keynote_env_add(char *name, char *value, struct environment **table,
+ u_int hashsize, int flags)
+{
+ struct environment *en;
+ u_int h, i;
+
+ en = calloc(1, sizeof(struct environment));
+ if (en == (struct environment *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ en->env_name = strdup(name);
+ if (en->env_name == (char *) NULL)
+ {
+ keynote_free_env(en);
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (flags & ENVIRONMENT_FLAG_REGEX) /* Regular expression for name */
+ {
+ if ((i = regcomp(&(en->env_regex), name, REG_EXTENDED)) != 0)
+ {
+ keynote_free_env(en);
+ if (i == REG_ESPACE)
+ keynote_errno = ERROR_MEMORY;
+ else
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+ en->env_flags |= ENVIRONMENT_FLAG_REGEX;
+ }
+
+ if (flags & ENVIRONMENT_FLAG_FUNC) /* Callback registration */
+ {
+ en->env_value = value;
+ en->env_flags |= ENVIRONMENT_FLAG_FUNC;
+ ((char * (*) (char *))en->env_value)(KEYNOTE_CALLBACK_INITIALIZE);
+ if (keynote_errno != 0)
+ {
+ keynote_free_env(en);
+ return -1;
+ }
+ }
+ else
+ {
+ en->env_value = strdup(value);
+ if (en->env_value == (char *) NULL)
+ {
+ keynote_free_env(en);
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+ }
+
+ /*
+ * This means that new assignments of existing variable will override
+ * the old ones.
+ */
+ h = keynote_stringhash(name, hashsize);
+ en->env_next = table[h];
+ table[h] = en;
+ return RESULT_TRUE;
+}
+
+/*
+ * Cleanup an environment table.
+ */
+void
+keynote_env_cleanup(struct environment **table, u_int hashsize)
+{
+ struct environment *en2;
+
+ if ((hashsize == 0) || (table == (struct environment **) NULL))
+ return;
+
+ while (hashsize > 0)
+ {
+ while (table[hashsize - 1] != (struct environment *) NULL)
+ {
+ en2 = table[hashsize - 1]->env_next;
+ keynote_free_env(table[hashsize - 1]);
+ table[hashsize - 1] = en2;
+ }
+
+ hashsize--;
+ }
+}
+
+/*
+ * Zero out the attribute structures, seed the RNG.
+ */
+static int
+keynote_init_environment(void)
+{
+#ifdef CRYPTO
+#if defined(KEYNOTERNDFILENAME)
+ int cnt = KEYNOTE_RAND_INIT_LEN, i;
+
+ do
+ {
+ if ((i = RAND_load_file(KEYNOTERNDFILENAME, cnt)) <= 0)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ cnt -= i;
+ } while (cnt > 0);
+#else /* KEYNOTERNDFILENAME */
+#error "You need to seed the RNG."
+#endif /* KEYNOTERNDFILENAME */
+#endif /* CRYPTO */
+ memset(keynote_current_session->ks_env_table, 0,
+ HASHTABLESIZE * sizeof(struct environment *));
+ memset(keynote_current_session->ks_assertion_table, 0,
+ HASHTABLESIZE * sizeof(struct assertion *));
+ keynote_current_session->ks_env_regex = (struct environment *) NULL;
+
+ if (keynote_env_add("_ACTION_AUTHORIZERS",
+ (char *) keynote_get_action_authorizers,
+ keynote_current_session->ks_env_table, HASHTABLESIZE,
+ ENVIRONMENT_FLAG_FUNC) != RESULT_TRUE)
+ return -1;
+
+ if (keynote_env_add("_VALUES", (char *) keynote_get_values,
+ keynote_current_session->ks_env_table, HASHTABLESIZE,
+ ENVIRONMENT_FLAG_FUNC) != RESULT_TRUE)
+ return -1;
+
+ return RESULT_TRUE;
+}
+
+/*
+ * Return the index of argument in keynote_values[].
+ */
+int
+keynote_retindex(char *s)
+{
+ int i;
+
+ for (i = 0; i < keynote_current_session->ks_values_num; i++)
+ if (!strcmp(s, keynote_current_session->ks_values[i]))
+ return i;
+
+ return -1;
+}
+
+/*
+ * Find a session by its id.
+ */
+struct keynote_session *
+keynote_find_session(int sessid)
+{
+ unsigned int h = sessid % SESSIONTABLESIZE;
+ struct keynote_session *ks;
+
+ for (ks = keynote_sessions[h];
+ ks != (struct keynote_session *) NULL;
+ ks = ks->ks_next)
+ if (ks->ks_id == sessid)
+ return ks;
+
+ return (struct keynote_session *) NULL;
+}
+
+/*
+ * Add a session in the hash table.
+ */
+static void
+keynote_add_session(struct keynote_session *ks)
+{
+ unsigned int h = ks->ks_id % SESSIONTABLESIZE;
+
+ ks->ks_next = keynote_sessions[h];
+ if (ks->ks_next != (struct keynote_session *) NULL)
+ ks->ks_next->ks_prev = ks;
+
+ keynote_sessions[h] = ks;
+}
+
+/*
+ * Initialize a KeyNote session.
+ */
+int
+kn_init(void)
+{
+ keynote_errno = 0;
+ keynote_current_session = (struct keynote_session *) calloc(1, sizeof(struct keynote_session));
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ while (keynote_find_session(sessioncounter) !=
+ (struct keynote_session *) NULL)
+ {
+ sessioncounter++;
+ if (sessioncounter < 0)
+ sessioncounter = 0;
+ }
+
+ keynote_current_session->ks_id = sessioncounter++;
+ keynote_init_environment();
+ keynote_add_session(keynote_current_session);
+ return keynote_current_session->ks_id;
+}
+
+/*
+ * Close a session.
+ */
+int
+kn_close(int sessid)
+{
+ struct keynote_session *ks;
+ struct assertion *as, *as2;
+ int i;
+
+ keynote_errno = 0;
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ ks = keynote_current_session;
+
+ /* Cleanup environment */
+ keynote_env_cleanup(ks->ks_env_table, HASHTABLESIZE);
+ keynote_env_cleanup(&(ks->ks_env_regex), 1);
+
+ /* Cleanup assertions */
+ for (i = 0; i < HASHTABLESIZE; i++)
+ for (as = ks->ks_assertion_table[i];
+ as != (struct assertion *) NULL;
+ as = as2)
+ {
+ as2 = as->as_next;
+ keynote_free_assertion(as);
+ }
+
+ /* Cleanup action authorizers */
+ keynote_keylist_free(ks->ks_action_authorizers);
+
+ /* Unlink from chain */
+ if (ks->ks_prev == (struct keynote_session *) NULL)
+ {
+ keynote_sessions[ks->ks_id % SESSIONTABLESIZE] = ks->ks_next;
+ if (ks->ks_next != (struct keynote_session *) NULL)
+ ks->ks_next->ks_prev = (struct keynote_session *) NULL;
+
+ }
+ else
+ {
+ ks->ks_prev->ks_next = ks->ks_next;
+ if (ks->ks_next != (struct keynote_session *) NULL)
+ ks->ks_next->ks_prev = ks->ks_prev;
+ }
+
+ free(ks);
+ keynote_current_session = (struct keynote_session *) NULL;
+ return 0;
+}
+
+/*
+ * Add an action attribute.
+ */
+int
+kn_add_action(int sessid, char *name, char *value, int flags)
+{
+ int i;
+
+ keynote_errno = 0;
+ if ((name == (char *) NULL) || (value == (char *) NULL) ||
+ (name[0] == '_'))
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ if (flags & ENVIRONMENT_FLAG_REGEX)
+ i = keynote_env_add(name, value,
+ &(keynote_current_session->ks_env_regex), 1, flags);
+ else
+ i = keynote_env_add(name, value, keynote_current_session->ks_env_table,
+ HASHTABLESIZE, flags);
+
+ if (i == RESULT_TRUE)
+ return 0;
+ else
+ return -1;
+}
+
+/*
+ * Remove an action attribute.
+ */
+int
+kn_remove_action(int sessid, char *name)
+{
+ int i;
+
+ keynote_errno = 0;
+ if ((name == (char *) NULL) || (name[0] == '_'))
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ i = keynote_env_delete(name, keynote_current_session->ks_env_table,
+ HASHTABLESIZE);
+ if (i == RESULT_TRUE)
+ return 0;
+
+ i = keynote_env_delete(name, &(keynote_current_session->ks_env_regex),
+ HASHTABLESIZE);
+ if (i == RESULT_TRUE)
+ return 0;
+
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+}
+
+/*
+ * Execute a query.
+ */
+int
+kn_do_query(int sessid, char **returnvalues, int numvalues)
+{
+ struct assertion *as;
+ int i;
+
+ keynote_errno = 0;
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ /* Check that we have at least one action authorizer */
+ if (keynote_current_session->ks_action_authorizers ==
+ (struct keylist *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+
+ /*
+ * We may use already set returnvalues, or use new ones,
+ * but we must have some before we can evaluate.
+ */
+ if ((returnvalues == (char **) NULL) &&
+ (keynote_current_session->ks_values == (char **) NULL))
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ /* Replace any existing returnvalues */
+ if (returnvalues != (char **) NULL)
+ {
+ keynote_current_session->ks_values = returnvalues;
+ keynote_current_session->ks_values_num = numvalues;
+ }
+
+ /* Reset assertion state from any previous queries */
+ for (i = 0; i < HASHTABLESIZE; i++)
+ for (as = keynote_current_session->ks_assertion_table[i];
+ as != (struct assertion *) NULL;
+ as = as->as_next)
+ {
+ as->as_kresult = KRESULT_UNTOUCHED;
+ as->as_result = 0;
+ as->as_internalflags &= ~ASSERT_IFLAG_PROCESSED;
+ as->as_error = 0;
+ if (as->as_internalflags & ASSERT_IFLAG_WEIRDSIG)
+ as->as_sigresult = SIGRESULT_UNTOUCHED;
+ }
+
+ return keynote_evaluate_query();
+}
+
+/*
+ * Return assertions that failed, by error type.
+ */
+int
+kn_get_failed(int sessid, int type, int num)
+{
+ struct assertion *as;
+ int i;
+
+ if ((keynote_current_session == (struct keynote_session *) NULL) ||
+ (keynote_current_session->ks_id != sessid))
+ {
+ keynote_current_session = keynote_find_session(sessid);
+ if (keynote_current_session == (struct keynote_session *) NULL)
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+ }
+ }
+
+ for (i = 0; i < HASHTABLESIZE; i++)
+ for (as = keynote_current_session->ks_assertion_table[i];
+ as != (struct assertion *) NULL;
+ as = as->as_next)
+ switch (type)
+ {
+ case KEYNOTE_ERROR_ANY:
+ if ((as->as_error != 0) ||
+ ((as->as_sigresult != SIGRESULT_TRUE) &&
+ !(as->as_flags & ASSERT_FLAG_LOCAL)))
+ if (num-- == 0) /* Return it if it's the num-th found */
+ return as->as_id;
+ break;
+
+ case KEYNOTE_ERROR_MEMORY:
+ if (as->as_error == ERROR_MEMORY)
+ if (num-- == 0)
+ return as->as_id;
+ break;
+
+ case KEYNOTE_ERROR_SYNTAX:
+ if (as->as_error == ERROR_SYNTAX)
+ if (num-- == 0)
+ return as->as_id;
+ break;
+
+ case KEYNOTE_ERROR_SIGNATURE:
+ if ((as->as_sigresult != SIGRESULT_TRUE) &&
+ !(as->as_flags & ASSERT_FLAG_LOCAL))
+ if (num-- == 0)
+ return as->as_id;
+ break;
+ }
+
+ keynote_errno = ERROR_NOTFOUND;
+ return -1;
+}
+
+/*
+ * Simple API for doing a single KeyNote query.
+ */
+int
+kn_query(struct environment *env, char **retvalues, int numval,
+ char **trusted, int *trustedlen, int numtrusted,
+ char **untrusted, int *untrustedlen, int numuntrusted,
+ char **authorizers, int numauthorizers)
+{
+ struct environment *en;
+ int sessid, i, serrno;
+
+ keynote_errno = 0;
+ if ((sessid = kn_init()) == -1)
+ return -1;
+
+ /* Action set */
+ for (en = env; en != (struct environment *) NULL; en = en->env_next)
+ kn_add_action(sessid, en->env_name, en->env_value, en->env_flags);
+
+ /* Locally trusted assertions */
+ for (i = 0; i < numtrusted; i++)
+ kn_add_assertion(sessid, trusted[i], trustedlen[i], ASSERT_FLAG_LOCAL);
+
+ /* Untrusted assertions */
+ for (i = 0; i < numuntrusted; i++)
+ kn_add_assertion(sessid, untrusted[i], untrustedlen[i], 0);
+
+ /* Authorizers */
+ for (i = 0; i < numauthorizers; i++)
+ kn_add_authorizer(sessid, authorizers[i]);
+
+ i = kn_do_query(sessid, retvalues, numval);
+ serrno = keynote_errno;
+ kn_close(sessid);
+
+ if (serrno)
+ keynote_errno = serrno;
+
+ return i;
+}
+
+/*
+ * Read a buffer, break it up in assertions.
+ */
+char **
+kn_read_asserts(char *buffer, int bufferlen, int *numassertions)
+{
+ int bufsize = 32, i, flag, valid;
+ char **buf, **tempbuf, *ptr;
+
+ keynote_errno = 0;
+
+ if (buffer == (char *) NULL)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char **) NULL;
+ }
+
+ buf = (char **) calloc(bufsize, sizeof(char *));
+ if (buf == (char **) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char **) NULL;
+ }
+
+ /*
+ * We'll go through the whole buffer looking for consecutive newlines,
+ * which imply newline separation. We use the valid flag to keep
+ * track of whether there may be an assertion after the last pair of
+ * newlines, or whether there may be an assertion in the buffer to
+ * begin with, if there are no consecutive newlines.
+ */
+ for (i = 0, flag = 0, valid = 0, *numassertions = 0, ptr = buffer;
+ i < bufferlen;
+ i++)
+ {
+ if (buffer[i] == '\n')
+ {
+ if (flag) /* Two newlines in a row, copy if there's anything */
+ {
+ if (valid) /* Something there */
+ {
+ /* Allocate enough memory */
+ buf[*numassertions] = (char *) calloc((buffer + i) - ptr
+ + 1, sizeof(char));
+ if (buf[*numassertions] == (char *) NULL)
+ {
+ /* Free any already-allocated strings */
+ for (flag = 0; flag < *numassertions; flag++)
+ free(buf[flag]);
+ free(buf);
+ keynote_errno = ERROR_MEMORY;
+ return (char **) NULL;
+ }
+
+ /* Copy string */
+ bcopy(ptr, buf[*numassertions], (buffer + i) - ptr);
+ (*numassertions)++;
+ }
+
+ valid = 0; /* Reset */
+ flag = 0;
+ ptr = buffer + i + 1; /* Point right after this newline */
+
+ /* See if we need to resize the buffer */
+ if (*numassertions > bufsize - 4)
+ {
+ /* Allocate twice the space */
+ tempbuf = (char **) realloc(buf, 2 * bufsize *
+ sizeof(char *));
+ if (tempbuf == (char **) NULL)
+ {
+ for (flag = 0; flag < *numassertions; flag++)
+ free(buf[flag]);
+ free(buf);
+ keynote_errno = ERROR_MEMORY;
+ return (char **) NULL;
+ }
+
+ free(buf); /* Free old buffer */
+ buf = tempbuf;
+ bufsize *= 2;
+ }
+ }
+ else
+ flag = 1; /* One newline so far */
+
+ continue;
+ }
+ else
+ flag = 0;
+
+ if (!isspace(buffer[i]))
+ valid = 1;
+ }
+
+ /*
+ * There may be a valid assertion after the last pair of newlines.
+ * Notice that because of the resizing check above, there will be
+ * a valid memory location to store this last string.
+ */
+ if (valid)
+ {
+ /* This one's easy, we can just use strdup() */
+ if ((buf[*numassertions] = strdup(ptr)) == (char *) NULL)
+ {
+ for (flag = 0; flag < *numassertions; flag++)
+ free(buf[flag]);
+ free(buf);
+ keynote_errno = ERROR_MEMORY;
+ return (char **) NULL;
+ }
+ (*numassertions)++;
+ }
+
+ return buf;
+}
diff --git a/lib/libkeynote/environment.h b/lib/libkeynote/environment.h
new file mode 100644
index 00000000000..5baba46e290
--- /dev/null
+++ b/lib/libkeynote/environment.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: environment.h,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef __ENVIRONMENT_H__
+#define __ENVIRONMENT_H__
+
+#include "keynote.h"
+
+#define KEYNOTE_RAND_INIT_LEN 1024
+
+/*
+ * These can be changed to reflect more assertions/session or more
+ * sessions respectively
+ */
+#define HASHTABLESIZE 37
+#define SESSIONTABLESIZE 37
+
+struct keynote_session
+{
+ int ks_id;
+ int ks_assertioncounter;
+ int ks_values_num;
+ struct environment *ks_env_table[HASHTABLESIZE];
+ struct environment *ks_env_regex;
+ struct keylist *ks_action_authorizers;
+ struct assertion *ks_assertion_table[HASHTABLESIZE];
+ char **ks_values;
+ char *ks_authorizers_cache;
+ char *ks_values_cache;
+ struct keynote_session *ks_prev;
+ struct keynote_session *ks_next;
+};
+
+int keynote_env_add(char *, char *, struct environment **, u_int, int);
+char *keynote_env_lookup(char *, struct environment **, u_int);
+int keynote_env_delete(char *, struct environment **, u_int);
+struct environment *keynote_get_envlist(char *, char *, int);
+void keynote_env_cleanup(struct environment **, u_int);
+struct keynote_session *keynote_find_session(int);
+void keynote_free_env(struct environment *);
+int keynote_sremove_assertion(int, int);
+u_int keynote_stringhash(char *, u_int);
+void keynote_cleanup_kth(void);
+int keynote_retindex(char *);
+
+extern struct keynote_session *keynote_current_session;
+extern int keynote_returnvalue;
+extern int keynote_justrecord;
+#endif /* __ENVIRONMENT_H__ */
diff --git a/lib/libkeynote/keynote-keygen.c b/lib/libkeynote/keynote-keygen.c
new file mode 100644
index 00000000000..11dcfc371cc
--- /dev/null
+++ b/lib/libkeynote/keynote-keygen.c
@@ -0,0 +1,408 @@
+/* $OpenBSD: keynote-keygen.c,v 1.1 1999/05/23 22:11:06 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifdef WIN32
+#include <ctype.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "signature.h"
+
+#define DEFAULT_PUBLIC 0x10001
+
+void
+usage(void)
+{
+ fprintf(stderr, "Arguments:\n");
+ fprintf(stderr, "\t<AlgorithmName> <keysize> "
+ "<PublicKeyFile> <PrivateKeyFile> [<printf-offset> "
+ "<print-length>]\n");
+}
+
+#define SEED_LEN 40
+#define RND_BYTES 1024
+
+#define KEY_PRINT_OFFSET 12
+#define KEY_PRINT_LENGTH 50
+
+/*
+ * Print the specified number of spaces.
+ */
+void
+print_space(FILE *fp, int n)
+{
+ while (n--)
+ fprintf(fp, " ");
+}
+
+/*
+ * Output a key, properly formatted.
+ */
+void
+print_key(FILE *fp, char *algname, char *key, int start, int length)
+{
+ int i, k;
+
+ print_space(fp, start);
+ fprintf(fp, "\"%s", algname);
+
+ for (i = 0, k = strlen(algname) + 2; i < strlen(key); i++, k++)
+ {
+ if (k == length)
+ {
+ if (i == strlen(key))
+ {
+ fprintf(fp, "\"\n");
+ return;
+ }
+
+ fprintf(fp, "\\\n");
+ print_space(fp, start);
+ i--;
+ k = 0;
+ }
+ else
+ fprintf(fp, "%c", key[i]);
+ }
+
+ fprintf(fp, "\"\n");
+}
+
+#ifdef WIN32
+void
+#else
+int
+#endif
+main(int argc, char *argv[])
+{
+ int begin = KEY_PRINT_OFFSET, prlen = KEY_PRINT_LENGTH;
+#if defined(CRYPTO) || defined(PGPLIB)
+ char *foo, *privalgname, seed[SEED_LEN];
+ int alg, enc, ienc, len = 0, counter;
+ struct keynote_deckey dc;
+ unsigned long h;
+ DSA *dsa;
+ RSA *rsa;
+ FILE *fp;
+#if defined(KEYNOTERNDFILENAME)
+ int fd, cnt = RND_BYTES;
+#endif /* KEYNOTERNDFILENAME */
+#endif /* CRYPTO || PGPLIB */
+ char *algname;
+
+ if ((argc != 5) && (argc != 6) && (argc != 7))
+ {
+ usage();
+ exit(0);
+ }
+
+ /* Fix algorithm name */
+ if (argv[1][strlen(argv[1]) - 1] != ':')
+ {
+ fprintf(stderr, "Algorithm name [%s] should be terminated with a "
+ "colon, fixing.\n", argv[1]);
+ algname = (char *) calloc(strlen(argv[1]) + 2, sizeof(char));
+ if (algname == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+ strcpy(algname, argv[1]);
+ algname[strlen(algname)] = ':';
+ }
+ else
+ algname = argv[1];
+
+ if (argc > 5)
+ {
+ begin = atoi(argv[5]);
+ if (begin <= -1)
+ {
+ fprintf(stderr, "Erroneous value for print-offset parameter.\n");
+ exit(-1);
+ }
+ }
+
+ if (argc > 6)
+ {
+ prlen = atoi(argv[6]);
+ if (prlen <= 0)
+ {
+ fprintf(stderr, "Erroneous value for print-length parameter.\n");
+ exit(-1);
+ }
+ }
+
+ if (strlen(algname) + 2 > prlen)
+ {
+ fprintf(stderr, "Parameter ``print-length'' should be larger "
+ "than the length of AlgorithmName (%d)\n", strlen(algname));
+ exit(-1);
+ }
+
+#if defined(CRYPTO) || defined(PGPLIB)
+ alg = keynote_get_key_algorithm(algname, &enc, &ienc);
+ len = atoi(argv[2]);
+
+ if (len <= 0)
+ {
+ fprintf(stderr, "Invalid specified keysize %d\n", len);
+ exit(-1);
+ }
+#endif /* CRYPTO || PGPLIB */
+
+#if defined(CRYPTO)
+#if defined(KEYNOTERNDFILENAME)
+ fd = open(KEYNOTERNDFILENAME, O_RDONLY, 0);
+ if (fd < 0)
+ {
+ perror("open(\"/dev/urandom\")");
+ exit(-1);
+ }
+
+ for (h = 0; h < 5; h++)
+ {
+ if (read(fd, seed, SEED_LEN) <= 0)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ RAND_seed(seed, SEED_LEN);
+ }
+
+ if (read(fd, seed, SEED_LEN) < SEED_LEN)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ close(fd);
+
+ /* Make sure we read RND_BYTES bytes */
+ do
+ {
+ if ((fd = RAND_load_file(KEYNOTERNDFILENAME, cnt)) <= 0)
+ {
+ perror("RAND_load_file()");
+ exit(-1);
+ }
+
+ cnt -= fd;
+ } while (cnt > 0);
+
+#else /* KEYNOTERNDFILENAME */
+#error "No RNG available!"
+#endif /* KEYNOTERNDFILENAME */
+
+ if ((alg == KEYNOTE_ALGORITHM_DSA) &&
+ (ienc == INTERNAL_ENC_ASN1) &&
+ ((enc == ENCODING_HEX) || (enc == ENCODING_BASE64)))
+ {
+ dsa = DSA_generate_parameters(len, seed, SEED_LEN, &counter, &h, NULL
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+ , NULL
+#endif /* SSLEAY_VERSION_NUMBER */
+ );
+
+ if (dsa == (DSA *) NULL)
+ {
+ ERR_print_errors_fp(stderr);
+ exit(-1);
+ }
+
+ if (DSA_generate_key(dsa) != 1)
+ {
+ ERR_print_errors_fp(stderr);
+ exit(-1);
+ }
+
+ dc.dec_algorithm = KEYNOTE_ALGORITHM_DSA;
+ dc.dec_key = (void *) dsa;
+
+ foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PUBLIC_KEY);
+ if (foo == (char *) NULL)
+ {
+ fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
+ exit(-1);
+ }
+
+ if (!strcmp(argv[3], "-"))
+ fp = stdout;
+ else
+ {
+ fp = fopen(argv[3], "w");
+ if (fp == (FILE *) NULL)
+ {
+ perror("fopen()");
+ exit(-1);
+ }
+ }
+
+ print_key(fp, algname, foo, begin, prlen);
+ free(foo);
+
+ if (strcmp(argv[3], "-"))
+ fclose(fp);
+
+ foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PRIVATE_KEY);
+ if (foo == (char *) NULL)
+ {
+ fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
+ exit(-1);
+ }
+
+ if (!strcmp(argv[4], "-"))
+ {
+ fp = stdout;
+ if (!strcmp(argv[3], "-"))
+ printf("===========================\n");
+ }
+ else
+ {
+ fp = fopen(argv[4], "w");
+ if (fp == (FILE *) NULL)
+ {
+ perror("fopen()");
+ exit(-1);
+ }
+ }
+
+ privalgname = (char *) calloc(strlen(KEYNOTE_PRIVATE_KEY_PREFIX) +
+ strlen(foo) + 1, sizeof(char));
+ if (privalgname == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+ sprintf(privalgname, "%s%s", KEYNOTE_PRIVATE_KEY_PREFIX, algname);
+ print_key(fp, privalgname, foo, begin, prlen);
+ free(privalgname);
+ free(foo);
+
+ if (strcmp(argv[4], "-"))
+ fclose(fp);
+
+ exit(0);
+ }
+
+ if ((alg == KEYNOTE_ALGORITHM_RSA) &&
+ (ienc == INTERNAL_ENC_PKCS1) &&
+ ((enc == ENCODING_HEX) || (enc == ENCODING_BASE64)))
+ {
+ rsa = RSA_generate_key(len, DEFAULT_PUBLIC, NULL
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+ , NULL
+#endif /* SSLEAY_VERSION_NUMBER */
+ );
+
+ if (rsa == (RSA *) NULL)
+ {
+ ERR_print_errors_fp(stderr);
+ exit(-1);
+ }
+
+ dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
+ dc.dec_key = (void *) rsa;
+
+ foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PUBLIC_KEY);
+ if (foo == (char *) NULL)
+ {
+ fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
+ exit(-1);
+ }
+
+ if (!strcmp(argv[3], "-"))
+ fp = stdout;
+ else
+ {
+ fp = fopen(argv[3], "w");
+ if (fp == (FILE *) NULL)
+ {
+ perror("fopen()");
+ exit(-1);
+ }
+ }
+
+ print_key(fp, algname, foo, begin, prlen);
+ free(foo);
+
+ if (strcmp(argv[3], "-"))
+ fclose(fp);
+
+ foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PRIVATE_KEY);
+ if (foo == (char *) NULL)
+ {
+ fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
+ exit(-1);
+ }
+
+ if (!strcmp(argv[4], "-"))
+ {
+ fp = stdout;
+ if (!strcmp(argv[3], "-"))
+ printf("===========================\n");
+ }
+ else
+ {
+ fp = fopen(argv[4], "w");
+ if (fp == (FILE *) NULL)
+ {
+ perror("fopen()");
+ exit(-1);
+ }
+ }
+
+ privalgname = (char *) calloc(strlen(KEYNOTE_PRIVATE_KEY_PREFIX) +
+ strlen(foo) + 1, sizeof(char));
+ if (privalgname == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+ sprintf(privalgname, "%s%s", KEYNOTE_PRIVATE_KEY_PREFIX, algname);
+ print_key(fp, privalgname, foo, begin, prlen);
+ free(privalgname);
+ free(foo);
+
+ if (strcmp(argv[4], "-"))
+ fclose(fp);
+
+ exit(0);
+ }
+
+ /* More algorithms here */
+#endif /* CRYPTO */
+
+ fprintf(stderr, "Unknown/unsupported algorithm [%s]\n", algname);
+ exit(-1);
+}
diff --git a/lib/libkeynote/keynote-sign.c b/lib/libkeynote/keynote-sign.c
new file mode 100644
index 00000000000..467dcf5426a
--- /dev/null
+++ b/lib/libkeynote/keynote-sign.c
@@ -0,0 +1,250 @@
+/* $OpenBSD: keynote-sign.c,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <ctype.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "assertion.h"
+#include "signature.h"
+
+#define SIG_PRINT_OFFSET 12
+#define SIG_PRINT_LENGTH 50
+
+extern struct assertion *asp;
+
+void
+usage(void)
+{
+ fprintf(stderr, "Arguments:\n");
+ fprintf(stderr, "\t[-v] <AlgorithmName> <AssertionFile> "
+ "<PrivateKeyFile>\n");
+}
+
+/*
+ * Print the specified number of spaces.
+ */
+void
+print_space(FILE *fp, int n)
+{
+ while (n--)
+ fprintf(fp, " ");
+}
+
+/*
+ * Output a signature, properly formatted.
+ */
+void
+print_sig(FILE *fp, char *sig, int start, int length)
+{
+ int i, k;
+
+ print_space(fp, start);
+ fprintf(fp, "\"");
+
+ for (i = 0, k = 2; i < strlen(sig); i++, k++)
+ {
+ if (k == length)
+ {
+ if (i == strlen(sig))
+ {
+ fprintf(fp, "\"\n");
+ return;
+ }
+
+ fprintf(fp, "\\\n");
+ print_space(fp, start);
+ i--;
+ k = 0;
+ }
+ else
+ fprintf(fp, "%c", sig[i]);
+ }
+
+ fprintf(fp, "\"\n");
+}
+
+#ifdef WIN32
+void
+#else
+int
+#endif
+main(int argc, char *argv[])
+{
+ int begin = SIG_PRINT_OFFSET, prlen = SIG_PRINT_LENGTH;
+ char *buf, *buf2, *sig, *algname;
+ int fd, flg = 0, buflen;
+ struct stat sb;
+
+ if ((argc != 4) &&
+ (argc != 5))
+ {
+ usage();
+ exit(-1);
+ }
+
+ if (argc == 5)
+ {
+ if (!strcmp("-v", argv[1]))
+ flg = 1;
+ else
+ {
+ fprintf(stderr,
+ "Invalid first argument [%s] or too many arguments\n",
+ argv[1]);
+ exit(-1);
+ }
+ }
+
+ /* Fix algorithm name */
+ if (argv[1 + flg][strlen(argv[1 + flg]) - 1] != ':')
+ {
+ fprintf(stderr, "Algorithm name [%s] should be terminated with a "
+ "colon, fixing.\n", argv[1 + flg]);
+ algname = (char *) calloc(strlen(argv[1 + flg]) + 2, sizeof(char));
+ if (algname == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+ strcpy(algname, argv[1 + flg]);
+ algname[strlen(algname)] = ':';
+ }
+ else
+ algname = argv[1 + flg];
+
+ /* Read assertion */
+ fd = open(argv[2 + flg], O_RDONLY, 0);
+ if (fd < 0)
+ {
+ perror(argv[2 + flg]);
+ exit(-1);
+ }
+
+ if (fstat(fd, &sb) < 0)
+ {
+ perror("fstat()");
+ exit(-1);
+ }
+
+ if (sb.st_size == 0) /* Paranoid */
+ {
+ fprintf(stderr, "Error: zero-sized assertion-file.\n");
+ exit(-1);
+ }
+
+ buflen = sb.st_size + 1;
+ buf = (char *) calloc(buflen, sizeof(char));
+ if (buf == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+ if (read(fd, buf, buflen - 1) < 0)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ close(fd);
+
+ /* Read private key file */
+ fd = open(argv[3 + flg], O_RDONLY, 0);
+ if (fd < 0)
+ {
+ perror(argv[3 + flg]);
+ exit(-1);
+ }
+
+ if (fstat(fd, &sb) < 0)
+ {
+ perror("fstat()");
+ exit(-1);
+ }
+
+ if (sb.st_size == 0) /* Paranoid */
+ {
+ fprintf(stderr, "Illegal key-file size 0\n");
+ exit(-1);
+ }
+
+ buf2 = (char *) calloc(sb.st_size + 1, sizeof(char));
+ if (buf2 == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+ if (read(fd, buf2, sb.st_size) < 0)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ close(fd);
+
+ sig = kn_sign_assertion(buf, buflen, buf2, algname, flg);
+
+ /* Free buffers */
+ free(buf);
+ free(buf2);
+
+ if (sig == (char *) NULL)
+ {
+ switch (keynote_errno)
+ {
+ case ERROR_MEMORY:
+ fprintf(stderr, "Out of memory while creating signature.\n");
+ break;
+
+ case ERROR_SYNTAX:
+ fprintf(stderr, "Bad assertion or algorithm format, or "
+ "unsupported algorithm while creating signature.\n");
+ break;
+
+ default:
+ fprintf(stderr, "Unknown error while creating signature.\n");
+ }
+
+ exit(-1);
+ }
+
+ /* Print signature string */
+ print_sig(stdout, sig, begin, prlen);
+
+ free(sig); /* Just a reminder that the result is malloc'ed */
+
+ exit(0);
+}
diff --git a/lib/libkeynote/keynote-sigver.c b/lib/libkeynote/keynote-sigver.c
new file mode 100644
index 00000000000..c73af47982b
--- /dev/null
+++ b/lib/libkeynote/keynote-sigver.c
@@ -0,0 +1,137 @@
+/* $OpenBSD: keynote-sigver.c,v 1.1 1999/05/23 22:11:06 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <ctype.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "assertion.h"
+#include "signature.h"
+
+void
+usage(void)
+{
+ fprintf(stderr, "Arguments:\n");
+ fprintf(stderr, "\t<AssertionFile>\n");
+}
+
+#ifdef WIN32
+void
+#else
+int
+#endif
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ int fd, i;
+ char *buf;
+
+ if (argc != 2)
+ {
+ usage();
+ exit(0);
+ }
+
+ /* Open and read assertion file */
+ fd = open(argv[1], O_RDONLY, 0);
+ if (fd < 0)
+ {
+ perror("open()");
+ exit(-1);
+ }
+
+ if (fstat(fd, &sb) < 0)
+ {
+ perror("fstat()");
+ exit(-1);
+ }
+
+ if (sb.st_size == 0) /* Paranoid */
+ {
+ fprintf(stderr, "Illegal assertion-file size 0\n");
+ exit(-1);
+ }
+
+ buf = (char *) calloc(sb.st_size + 1, sizeof(char));
+ if (buf == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+ if (read(fd, buf, sb.st_size) < 0)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ close(fd);
+
+ i = kn_verify_assertion(buf, sb.st_size);
+ if (i == -1)
+ {
+ switch (keynote_errno)
+ {
+ case ERROR_MEMORY:
+ fprintf(stderr,
+ "Out of memory while parsing the assertion.\n");
+ break;
+
+ case ERROR_SYNTAX:
+ fprintf(stderr,
+ "Syntax error while parsing the assertion.\n");
+ break;
+
+ default:
+ fprintf(stderr,
+ "Unknown error while parsing the assertion.\n");
+ }
+
+ exit(-1);
+ }
+
+ free(buf);
+
+ if (i == SIGRESULT_TRUE)
+ fprintf(stdout, "Signature verified.\n");
+ else
+ {
+ if (keynote_errno != 0)
+ fprintf(stdout, "Signature could not be verified "
+ "(keynote_errno = %d).\n", keynote_errno);
+ else
+ fprintf(stdout, "Signature did not verify!\n");
+ }
+
+ exit(0);
+}
diff --git a/lib/libkeynote/keynote-ver.l b/lib/libkeynote/keynote-ver.l
new file mode 100644
index 00000000000..9084d8e6ad5
--- /dev/null
+++ b/lib/libkeynote/keynote-ver.l
@@ -0,0 +1,273 @@
+%{
+/* $OpenBSD: keynote-ver.l,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <string.h>
+#include "z.tab.h"
+#include "keynote.h"
+
+static void mystrncpy(char *, char *, int);
+
+extern int kvparse();
+%}
+string ([a-zA-Z])([a-zA-Z0-9_-])*
+vstring [a-zA-Z0-9][a-zA-Z0-9_]*
+litstring \"(([^\"\n])|(\\[\"\n\f\r\t.]))*\"
+comment "#"[^\n]*
+%s FIRSTPART MIDDLEPART SECONDPART KEYSTATE
+%pointer
+%option noyywrap yylineno never-interactive
+%%
+
+<MIDDLEPART>"=" {
+ BEGIN(SECONDPART);
+ return EQ;
+ }
+<FIRSTPART>{vstring} { kvlval.s.string = calloc(strlen(kvtext) + 1,
+ sizeof(char));
+ if (kvlval.s.string == (char *) NULL)
+ return ERROR_MEMORY;
+ strcpy(kvlval.s.string, kvtext);
+ BEGIN(MIDDLEPART);
+ return VSTRING;
+ }
+<KEYSTATE,SECONDPART>{string} { kvlval.s.string = calloc(strlen(kvtext) + 1,
+ sizeof(char));
+ if (kvlval.s.string == (char *) NULL)
+ return ERROR_MEMORY;
+ strncpy(kvlval.s.string, kvtext,
+ strlen(kvtext));
+ BEGIN(FIRSTPART);
+ return STRING;
+ }
+<KEYSTATE,SECONDPART>{litstring} { kvlval.s.string = calloc(strlen(kvtext) - 1,
+ sizeof(char));
+ if (kvlval.s.string == (char *) NULL)
+ return ERROR_MEMORY;
+ mystrncpy(kvlval.s.string, kvtext + 1,
+ strlen(kvtext) - 2);
+ BEGIN(FIRSTPART);
+ return STRING;
+ }
+<FIRSTPART,KEYSTATE>{comment} ;
+[ \t\n] ;
+. return ERROR_SYNTAX;
+
+%%
+
+/*
+ * Return RESULT_TRUE if character is octal digit, RESULT_FALSE otherwise.
+ */
+static int
+is_octal(char c)
+{
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ return RESULT_TRUE;
+
+ default:
+ return RESULT_FALSE;
+ }
+}
+
+/*
+ * Return octal value (non-zero) if argument starts with such a
+ * representation, otherwise 0.
+ */
+static unsigned char
+get_octal(char *s, int len, int *adv)
+{
+ unsigned char res = 0;
+
+ if (*s == '0')
+ {
+ if (len > 0)
+ {
+ if (is_octal(*(s + 1)))
+ {
+ res = *(s + 1) - '0';
+ *adv = 2;
+
+ if (is_octal(*(s + 2)) && (len - 1 > 0))
+ {
+ res = res * 8 + (*(s + 2) - '0');
+ *adv = 3;
+ }
+ }
+ }
+ }
+ else
+ if (is_octal(*s) && (len - 1 > 0)) /* Non-zero leading */
+ {
+ if (is_octal(*(s + 1)) &&
+ is_octal(*(s + 2)))
+ {
+ *adv = 3;
+ res = (((*s) - '0') * 64) +
+ (((*(s + 1)) - '0') * 8) +
+ ((*(s + 2)) - '0');
+ }
+ }
+
+ return res;
+}
+
+/*
+ * Copy at most len characters to string s1 from string s2, taking
+ * care of escaped characters in the process. String s1 is assumed
+ * to have enough space, and be zero'ed.
+ */
+static void
+mystrncpy(char *s1, char *s2, int len)
+{
+ unsigned char c;
+ int advance;
+
+ if (len == 0)
+ return;
+
+ while (len-- > 0)
+ {
+ if (*s2 == '\\')
+ {
+ s2++;
+
+ if (len-- <= 0)
+ break;
+
+ if (*s2 == '\n')
+ {
+ while (isspace(*(++s2)) && (len-- > 0))
+ ;
+ }
+ else
+ if ((c = get_octal(s2, len, &advance)) != 0)
+ {
+ len -= advance - 1;
+ s2 += advance;
+ *s1++ = c;
+ }
+ else
+ if (*s2 == 'n') /* Newline */
+ {
+ *s1++ = '\n';
+ s2++;
+ }
+ else
+ if (*s2 == 't') /* Tab */
+ {
+ *s1++ = '\t';
+ s2++;
+ }
+ else
+ if (*s2 == 'r') /* Linefeed */
+ {
+ *s1++ = '\r';
+ s2++;
+ }
+ else
+ if (*s2 == 'f') /* Formfeed */
+ {
+ *s1++ = '\f';
+ s2++;
+ }
+ else
+ if ((*s1++ = *s2++) == 0)
+ break;
+
+ continue;
+ }
+
+ if ((*s1++ = *s2++) == 0)
+ break;
+ }
+}
+
+/*
+ * Parse a file that contains environment variable/value pairs.
+ * Return -1 on failure.
+ */
+int
+read_environment(char *filename)
+{
+ YY_BUFFER_STATE kvfoo;
+ FILE *fp;
+ int i;
+
+ fp = fopen(filename, "r");
+ if (fp == (FILE *) NULL)
+ {
+ perror(filename);
+ return -1;
+ }
+
+ kvfoo = kv_create_buffer(fp, YY_BUF_SIZE);
+ kv_switch_to_buffer(kvfoo);
+ BEGIN(FIRSTPART);
+ i = kvparse();
+ kv_delete_buffer(kvfoo);
+ fclose(fp);
+ switch (i)
+ {
+ case 0:
+ return 0;
+
+ case ERROR_MEMORY:
+ fprintf(stderr,
+ "Memory error while processing environment file <%s>\n",
+ filename);
+ return -1;
+ break;
+
+ case 1:
+ case ERROR_SYNTAX:
+ default:
+ fprintf(stderr, "Syntax error in environment file <%s>, line %d\n",
+ filename, kvlineno);
+ return -1;
+ }
+}
+
+/*
+ * Parse a key.
+ */
+void
+parse_key(char *buf)
+{
+ YY_BUFFER_STATE key_state;
+ int err;
+
+ key_state = kv_scan_string(buf);
+ BEGIN(KEYSTATE);
+ err = kvparse();
+ kv_delete_buffer(key_state);
+
+ if (err != 0)
+ if (keynote_errno == 0)
+ keynote_errno = ERROR_SYNTAX;
+}
diff --git a/lib/libkeynote/keynote-ver.y b/lib/libkeynote/keynote-ver.y
new file mode 100644
index 00000000000..204a5b1dbea
--- /dev/null
+++ b/lib/libkeynote/keynote-ver.y
@@ -0,0 +1,70 @@
+/* $OpenBSD: keynote-ver.y,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+%union {
+ struct s {
+ char *string;
+ } s;
+};
+%type <s.string> STRING VSTRING
+%token STRING VSTRING EQ
+%nonassoc EQ
+%start program
+%{
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "keynote.h"
+
+void kverror(char *);
+
+extern int kvlex();
+
+extern int sessid;
+%}
+%%
+
+program: /* Nothing */
+ | expr
+ | STRING { if (kn_add_authorizer(sessid, $1) != 0)
+ return keynote_errno;
+ free($1);
+ }
+
+expr: VSTRING EQ STRING { int i = kn_add_action(sessid, $1, $3, 0);
+
+ if (i != 0)
+ return i;
+ free($1);
+ free($3);
+ }
+ | expr VSTRING EQ STRING { int i = kn_add_action(sessid, $2, $4, 0);
+
+ if (i != 0)
+ return i;
+ free($2);
+ free($4);
+ }
+%%
+void
+kverror(char *s)
+{}
diff --git a/lib/libkeynote/keynote-verify.c b/lib/libkeynote/keynote-verify.c
new file mode 100644
index 00000000000..fde510c8667
--- /dev/null
+++ b/lib/libkeynote/keynote-verify.c
@@ -0,0 +1,447 @@
+/* $OpenBSD: keynote-verify.c,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <io.h>
+#include "getopt.h"
+#else
+#include <unistd.h>
+#ifdef NEED_GETOPT
+#include "getopt.h"
+#endif
+#endif
+
+#include "keynote.h"
+
+extern int read_environment(char *);
+extern void parse_key(char *);
+
+int sessid;
+
+void
+usage(void)
+{
+ fprintf(stderr, "Arguments:\n");
+ fprintf(stderr, "\t-h: This message\n");
+ fprintf(stderr,
+ "\t-r <valuelist>: Comma separated, ordered return-value list\n");
+ fprintf(stderr, "\t-e <filename>: Environment settings\n");
+ fprintf(stderr, "\t-l <filename>: Trusted (local) assertion\n");
+ fprintf(stderr, "\t-k <filename>: File containing key\n");
+ fprintf(stderr, "Followed by a list of:\n");
+ fprintf(stderr, "\t<filename>: Non-local assertion\n");
+}
+
+#ifdef WIN32
+void
+#else
+int
+#endif
+main(int argc, char *argv[])
+{
+#ifdef LoopTesting
+ int loopvar = 1000;
+#endif /* LoopTesting */
+ int fd, i, ch, se = 0, cl = 8192, sk = 0, sl = 0, p, ac = argc;
+ char *buf, **av = argv, **retv, **foov, *ptr;
+ int numretv = 16, numret = 0, sn;
+ struct stat sb;
+
+ if (argc == 1)
+ {
+ usage();
+ exit(-1);
+ }
+
+ if ((buf = (char *) calloc(cl, sizeof(char))) == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+#ifdef LoopTesting
+ while(loopvar--) {
+#endif /* LoopTesting */
+
+ if ((retv = (char **) calloc(numretv, sizeof(char *))) == (char **) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+ /* "ac" and "av" are used for stress-testing, ignore otherwise */
+ argv = av;
+ argc = ac;
+ sn = 0;
+ opterr = 0;
+
+ sessid = kn_init();
+ if (sessid == -1)
+ {
+ fprintf(stderr, "kn_init() failed (errno %d).\n", keynote_errno);
+ exit(keynote_errno);
+ }
+
+ while ((ch = getopt(argc, argv, "hqistl:e:k:r:")) != -1)
+ {
+ switch (ch)
+ {
+ case 'e':
+ if (read_environment(optarg) == -1)
+ exit(-1);
+ se = 1;
+ break;
+
+ case 'k':
+ sk = 1;
+
+ if ((fd = open(optarg, O_RDONLY, 0)) < 0)
+ {
+ perror("open()");
+ exit(-1);
+ }
+
+ if (fstat(fd, &sb) < 0)
+ {
+ perror("fstat()");
+ exit(-1);
+ }
+
+ if (sb.st_size > cl - 1)
+ {
+ free(buf);
+ cl = sb.st_size + 1;
+ buf = (char *) calloc(cl, sizeof(char));
+ if (buf == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+ }
+
+ i = read(fd, buf, sb.st_size);
+ if (i < 0)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ close(fd);
+
+ parse_key(buf);
+ switch (keynote_errno)
+ {
+ case 0: /* No errors */
+ break;
+
+ case ERROR_SYNTAX:
+ fprintf(stderr, "Syntax error adding authorizer "
+ "%s\n", optarg);
+ exit(-1);
+
+ case ERROR_MEMORY:
+ perror("Out of memory.\n");
+ exit(-1);
+
+ default:
+ fprintf(stderr, "Unknown error (%d).\n",
+ keynote_errno);
+ }
+
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+
+ case 'r':
+ if (sn != 0)
+ {
+ fprintf(stderr,
+ "Do not define two sets of return values.\n");
+ exit(-1);
+ }
+
+ sn = 1;
+
+ for (numret = 0;
+ (ptr = index(optarg, ',')) != (char *) NULL;
+ numret++)
+ {
+ /* Running out of memory */
+ if (numret > numretv - 3)
+ {
+ numretv *= 2;
+ foov = (char **) calloc(numretv, sizeof(char **));
+ if (foov == (char **) NULL)
+ {
+ /*
+ * If this were a real program, we 'd be freeing
+ * retv here. Since we're exiting, we can be a
+ * little sloppy.
+ */
+ perror("calloc()");
+ exit(-1);
+ }
+
+ bcopy(retv, foov, numretv * sizeof(char **));
+ free(retv);
+ retv = foov;
+ }
+
+ retv[numret] = (char *) calloc((ptr - optarg) + 1,
+ sizeof(char));
+ if (retv[numret] == (char *) NULL)
+ {
+ /* Comment from above applies here as well */
+ perror("calloc()");
+ exit(-1);
+ }
+
+ /* Copy */
+ bcopy(optarg, retv[numret], ptr - optarg);
+ optarg = ptr + 1;
+ }
+
+ /* Last component */
+ retv[numret] = (char *) strdup(optarg);
+ if (retv[numret] == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+
+ numret++;
+ break;
+
+ case 'l':
+ if ((fd = open(optarg, O_RDONLY, 0)) < 0)
+ {
+ perror("open()");
+ exit(-1);
+ }
+
+ if (fstat(fd, &sb) < 0)
+ {
+ perror("fstat()");
+ exit(-1);
+ }
+
+ if (sb.st_size > cl - 1)
+ {
+ free(buf);
+ cl = sb.st_size + 1;
+ buf = (char *) calloc(cl, sizeof(char));
+ if (buf == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+ }
+
+ i = read(fd, buf, sb.st_size);
+ if (i < 0)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ close(fd);
+ p = kn_add_assertion(sessid, buf, i, ASSERT_FLAG_LOCAL);
+ if (p == -1)
+ {
+ fprintf(stderr,
+ "Error for assertion in file <%s>, errno %d.\n",
+ optarg, keynote_errno);
+ keynote_errno = 0;
+ }
+
+ memset(buf, 0, sb.st_size);
+ sl = 1;
+ break;
+
+ case '?':
+ default:
+ usage();
+ exit(-1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 1;
+
+#ifdef LoopTesting
+ optreset = 1;
+#endif /* LoopTesting */
+
+ if (sn == 0)
+ {
+ fprintf(stderr,
+ "Should set return values before evaluations begin.\n");
+ exit(-1);
+ }
+
+ if (se == 0)
+ {
+ fprintf(stderr, "Should set environment before evaluations begin.\n");
+ exit(-1);
+ }
+
+ if (sk == 0)
+ {
+ fprintf(stderr, "Should specify at least one action authorizer.\n");
+ exit(-1);
+ }
+
+ if (sl == 0)
+ {
+ fprintf(stderr,
+ "Should specify at least one trusted assertion (POLICY).\n");
+ exit(-1);
+ }
+
+ while (argc--)
+ {
+ if ((fd = open(argv[argc], O_RDONLY, 0)) < 0)
+ {
+ perror("open()");
+ exit(-1);
+ }
+
+ if (fstat(fd, &sb) < 0)
+ {
+ perror("fstat()");
+ exit(-1);
+ }
+
+ if (sb.st_size > cl - 1)
+ {
+ free(buf);
+ cl = sb.st_size + 1;
+ buf = (char *) calloc(cl, sizeof(char));
+ if (buf == (char *) NULL)
+ {
+ perror("calloc()");
+ exit(-1);
+ }
+ }
+
+ i = read(fd, buf, sb.st_size);
+ if (i < 0)
+ {
+ perror("read()");
+ exit(-1);
+ }
+
+ close(fd);
+ p = kn_add_assertion(sessid, buf, i, 0);
+ if (p == -1)
+ {
+ fprintf(stderr, "Error for assertion in file <%s>, errno %d.\n",
+ argv[argc], keynote_errno);
+ keynote_errno = 0;
+ }
+
+ memset(buf, 0, sb.st_size);
+ }
+
+ p = kn_do_query(sessid, retv, numret); /* Evaluation time */
+
+#ifndef LoopTesting
+ printf("Query result = ");
+
+ switch (keynote_errno)
+ {
+ case ERROR_MEMORY:
+ printf("<out of memory>\n");
+ exit(-1);
+
+ case ERROR_SYNTAX:
+ printf("<uninitialized authorizers or all POLICY "
+ "assertions are malformed!>\n");
+ exit(-1);
+
+ case ERROR_NOTFOUND:
+ printf("<session or other information not found!>\n");
+ exit(-1);
+
+ case 0: /* No errors */
+ break;
+
+ default:
+ printf("<should never happen (%d)!>\n", keynote_errno);
+ exit(-1);
+ }
+
+ printf("%s\n", retv[p]);
+#endif /* LoopTesting */
+
+ keynote_errno = 0;
+
+ while ((i = kn_get_failed(sessid, KEYNOTE_ERROR_MEMORY, 0)) != -1)
+ {
+ printf("Failed assertion %d due to memory error.\n", i);
+ kn_remove_assertion(sessid, i);
+ }
+
+ while ((i = kn_get_failed(sessid, KEYNOTE_ERROR_SYNTAX, 0)) != -1)
+ {
+ printf("Failed assertion %d due to syntax or semantic error.\n", i);
+ kn_remove_assertion(sessid, i);
+ }
+
+ while ((i = kn_get_failed(sessid, KEYNOTE_ERROR_SIGNATURE, 0)) != -1)
+ {
+ printf("Failed assertion %d due to signature verification failure.\n",
+ i);
+ kn_remove_assertion(sessid, i);
+ }
+
+ while ((i = kn_get_failed(sessid, KEYNOTE_ERROR_ANY, 0)) != -1)
+ {
+ printf("Failed assertion %d due to unspecified error.\n", i);
+ kn_remove_assertion(sessid, i);
+ }
+
+ kn_close(sessid);
+
+#ifdef LoopTesting
+ }
+#endif /* LoopTesting */
+
+ /* This is a reminder that return values are not free'ed by KeyNote */
+ for (sn = 0; sn < numret; sn++)
+ free(retv[sn]);
+ free(retv);
+ retv = (char **) NULL;
+
+ exit(0);
+}
diff --git a/lib/libkeynote/keynote.h b/lib/libkeynote/keynote.h
new file mode 100644
index 00000000000..2ae97f85919
--- /dev/null
+++ b/lib/libkeynote/keynote.h
@@ -0,0 +1,195 @@
+/* $OpenBSD: keynote.h,v 1.1 1999/05/23 22:11:04 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef _KEYNOTE_H_
+#define _KEYNOTE_H_
+
+#include <regex.h>
+
+#ifdef CRYPTO
+#include "ssl/crypto.h"
+#include "ssl/dsa.h"
+#include "ssl/rsa.h"
+#include "ssl/sha.h"
+#include "ssl/md5.h"
+#include "ssl/err.h"
+#include "ssl/rand.h"
+#include "ssl/x509.h"
+#endif /* CRYPTO */
+
+#ifdef WIN32
+#define u_int unsigned int
+#define u_char unsigned char
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+#define open _open
+#define read _read
+#define close _close
+#endif
+
+#if defined(__OpenBSD__) || defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
+#define KEYNOTERNDFILENAME "/dev/urandom"
+#endif /* __OpenBSD__ || linux || __FreeBSD__ || __NetBSD__ */
+
+struct environment
+{
+ char *env_name;
+ char *env_value;
+ int env_flags;
+ regex_t env_regex;
+ struct environment *env_next;
+};
+
+struct keynote_deckey
+{
+ int dec_algorithm;
+ void *dec_key;
+};
+
+struct keynote_binary
+{
+ int bn_len;
+ char *bn_key;
+};
+
+#define SIG_DSA_SHA1_HEX "sig-dsa-sha1-hex:"
+#define SIG_DSA_SHA1_HEX_LEN strlen(SIG_DSA_SHA1_HEX)
+#define SIG_DSA_SHA1_BASE64 "sig-dsa-sha1-base64:"
+#define SIG_DSA_SHA1_BASE64_LEN strlen(SIG_DSA_SHA1_BASE64)
+#define SIG_RSA_SHA1_PKCS1_HEX "sig-rsa-sha1-hex:"
+#define SIG_RSA_SHA1_PKCS1_HEX_LEN strlen(SIG_RSA_SHA1_PKCS1_HEX)
+#define SIG_RSA_SHA1_PKCS1_BASE64 "sig-rsa-sha1-base64:"
+#define SIG_RSA_SHA1_PKCS1_BASE64_LEN strlen(SIG_RSA_SHA1_PKCS1_BASE64)
+#define SIG_RSA_MD5_PKCS1_HEX "sig-rsa-md5-hex:"
+#define SIG_RSA_MD5_PKCS1_HEX_LEN strlen(SIG_RSA_MD5_PKCS1_HEX)
+#define SIG_RSA_MD5_PKCS1_BASE64 "sig-rsa-md5-base64:"
+#define SIG_RSA_MD5_PKCS1_BASE64_LEN strlen(SIG_RSA_MD5_PKCS1_BASE64)
+#define SIG_ELGAMAL_SHA1_HEX "sig-elgamal-sha1-hex:"
+#define SIG_ELGAMAL_SHA1_HEX_LEN strlen(SIG_ELGAMAL_SHA1_HEX)
+#define SIG_ELGAMAL_SHA1_BASE64 "sig-elgamal-sha1-base64:"
+#define SIG_ELGAMAL_SHA1_BASE64_LEN strlen(SIG_ELGAMAL_SHA1_BASE64)
+#define SIG_PGP_NATIVE "sig-pgp:"
+#define SIG_PGP_NATIVE_LEN strlen(SIG_PGP_NATIVE)
+#define SIG_X509_SHA1_BASE64 "sig-x509-sha1-base64:"
+#define SIG_X509_SHA1_BASE64_LEN strlen(SIG_X509_SHA1_BASE64)
+#define SIG_X509_SHA1_HEX "sig-x509-sha1-hex:"
+#define SIG_X509_SHA1_HEX_LEN strlen(SIG_X509_SHA1_HEX)
+
+#define SIGRESULT_UNTOUCHED 0
+#define SIGRESULT_FALSE 1
+#define SIGRESULT_TRUE 2
+
+#define ENVIRONMENT_FLAG_FUNC 0x0001 /* This is a callback function */
+#define ENVIRONMENT_FLAG_REGEX 0x0002 /* Regular expression for name */
+
+#define ASSERT_FLAG_LOCAL 0x0001 /*
+ * Trusted assertion -- means
+ * signature is not verified, and
+ * authorizer field can
+ * include symbolic names.
+ */
+#define ASSERT_FLAG_SIGGEN 0x0002 /*
+ * Be a bit more lax with the
+ * contents of the Signature:
+ * field; to be used in
+ * assertion signing only.
+ */
+#define ASSERT_FLAG_SIGVER 0x0004 /*
+ * To be used in signature verification
+ * only.
+ */
+#define RESULT_FALSE 0
+#define RESULT_TRUE 1
+
+#define KEYNOTE_CALLBACK_INITIALIZE "_KEYNOTE_CALLBACK_INITIALIZE"
+#define KEYNOTE_CALLBACK_CLEANUP "_KEYNOTE_CALLBACK_CLEANUP"
+
+#define KEYNOTE_VERSION_STRING "2"
+
+#define ERROR_MEMORY -1
+#define ERROR_SYNTAX -2
+#define ERROR_NOTFOUND -3
+#define ERROR_SIGN_FAILURE -4
+
+#define KEYNOTE_ALGORITHM_UNSPEC -1
+#define KEYNOTE_ALGORITHM_NONE 0
+#define KEYNOTE_ALGORITHM_DSA 1
+#define KEYNOTE_ALGORITHM_ELGAMAL 2
+#define KEYNOTE_ALGORITHM_PGP 3
+#define KEYNOTE_ALGORITHM_BINARY 4
+#define KEYNOTE_ALGORITHM_X509 5
+#define KEYNOTE_ALGORITHM_RSA 6
+
+#define KEYNOTE_ERROR_ANY 0
+#define KEYNOTE_ERROR_SYNTAX 1
+#define KEYNOTE_ERROR_MEMORY 2
+#define KEYNOTE_ERROR_SIGNATURE 3
+
+#define ENCODING_NONE 0
+#define ENCODING_HEX 1
+#define ENCODING_BASE64 2
+#define ENCODING_NATIVE 3 /* For things like PGP */
+
+#define INTERNAL_ENC_NONE 0
+#define INTERNAL_ENC_PKCS1 1
+#define INTERNAL_ENC_ASN1 2
+#define INTERNAL_ENC_NATIVE 3 /* For things like PGP */
+
+#define KEYNOTE_PUBLIC_KEY 0
+#define KEYNOTE_PRIVATE_KEY 1
+
+extern int keynote_errno;
+
+/* Session API */
+int kn_init(void);
+int kn_add_assertion(int, char *, int, int);
+int kn_remove_assertion(int, int);
+int kn_add_action(int, char *, char *, int);
+int kn_remove_action(int, char *);
+int kn_add_authorizer(int, char *);
+int kn_remove_authorizer(int, char *);
+int kn_do_query(int, char **, int);
+int kn_get_failed(int, int, int);
+int kn_close(int);
+
+/* Simple API */
+int kn_query(struct environment *, char **, int, char **, int *, int,
+ char **, int *, int, char **, int);
+
+/* Aux. routines */
+char **kn_read_asserts(char *, int, int *);
+
+/* ASCII-encoding API */
+int kn_encode_base64(unsigned char const *, unsigned int, char *,
+ unsigned int);
+int kn_decode_base64(char const *, unsigned char *, unsigned int);
+int kn_encode_hex(unsigned char *, char **, int);
+int kn_decode_hex(char *, char **);
+
+/* Key-encoding API */
+int kn_decode_key(struct keynote_deckey *, char *, int);
+char *kn_encode_key(struct keynote_deckey *, int, int, int);
+
+/* Crypto API */
+char *kn_sign_assertion(char *, int, char *, char *, int);
+int kn_verify_assertion(char *, int);
+#endif /* _KEYNOTE_H_ */
diff --git a/lib/libkeynote/keynote.l b/lib/libkeynote/keynote.l
new file mode 100644
index 00000000000..d1e4eb6235d
--- /dev/null
+++ b/lib/libkeynote/keynote.l
@@ -0,0 +1,749 @@
+%{
+/* $OpenBSD: keynote.l,v 1.1 1999/05/23 22:11:05 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#ifndef PILOT
+#include <time.h>
+#endif /* PILOT */
+#include <string.h>
+#include "k.tab.h"
+#include "environment.h"
+#include "assertion.h"
+#include "signature.h"
+
+static void mystrncpy(char *, char *, int);
+extern int knparse();
+
+struct lex_list
+{
+ int lex_type;
+ void *lex_s;
+};
+
+static struct lex_list *keynote_lex_list = (struct lex_list *) NULL;
+static int keynote_max_lex_list = 32;
+static int keynote_lex_counter = 0;
+static int first_tok = 0;
+
+int keynote_used_variable = 0;
+int keynote_exceptionflag = 0;
+int keynote_donteval = 0;
+
+char *keynote_privkey = (char *) NULL;
+
+struct environment *keynote_init_list = (struct environment *) NULL;
+struct environment *keynote_temp_list = (struct environment *) NULL;
+struct keylist *keynote_keypred_keylist = (struct keylist *) NULL;
+%}
+digit [0-9]
+specnumber [1-9][0-9]*
+number ({digit}+)
+flt ({digit}+"."{digit}+)
+vstring [a-zA-Z_][a-zA-Z0-9_]*
+white ((\\[\n][[:space:]]*))
+litstring \"(([^\"\n])|(\\[\"\n\f\r\t.]))*\"
+variable {vstring}
+comment "#"[^\n]*
+%s ACTIONSTRING LOCALINIT KEYPREDICATE SIGNERINIT KEYNOTEVERSION
+%pointer
+%option noyywrap never-interactive yylineno
+%%
+
+%{
+ /*
+ * Return a preset token, so we can have more than one grammars
+ * in yacc.
+ */
+ extern int first_tok;
+
+ if (first_tok)
+ {
+ int holdtok = first_tok;
+
+ first_tok = 0;
+ return holdtok;
+ }
+%}
+
+<KEYPREDICATE>{specnumber}"-of" {
+ knlval.intval = atoi(kntext);
+ return KOF;
+ }
+<ACTIONSTRING,KEYPREDICATE>"(" return OPENPAREN;
+<ACTIONSTRING,KEYPREDICATE>")" return CLOSEPAREN;
+<ACTIONSTRING,KEYPREDICATE>"&&" return AND;
+<ACTIONSTRING,KEYPREDICATE>"||" return OR;
+<ACTIONSTRING>"+" return PLUS;
+<ACTIONSTRING>"->" return HINT;
+<ACTIONSTRING>"{" return OPENBLOCK;
+<ACTIONSTRING>"}" return CLOSEBLOCK;
+<ACTIONSTRING>";" return SEMICOLON;
+<ACTIONSTRING>"!" return NOT;
+<ACTIONSTRING>"~=" return REGEXP;
+<ACTIONSTRING>"==" return EQ;
+<ACTIONSTRING>"!=" return NE;
+<ACTIONSTRING>"<" return LT;
+<ACTIONSTRING>">" return GT;
+<ACTIONSTRING>"<=" return LE;
+<ACTIONSTRING>">=" return GE;
+<ACTIONSTRING>"-" return MINUS;
+<ACTIONSTRING>"*" return MULT;
+<ACTIONSTRING>"/" return DIV;
+<ACTIONSTRING>"%" return MOD;
+<ACTIONSTRING>"^" return EXP;
+"." return DOTT;
+<ACTIONSTRING>"true" return TRUE;
+<ACTIONSTRING>"false" return FALSE;
+{comment} /* eat up comments */
+<LOCALINIT>"=" return EQQ;
+<KEYPREDICATE>"," return COMMA;
+<ACTIONSTRING,KEYPREDICATE,SIGNERINIT,LOCALINIT>{variable} {
+ if (keynote_exceptionflag ||
+ keynote_donteval)
+ {
+ knlval.string = (char *) NULL;
+ return VARIABLE;
+ }
+
+ knlval.string = calloc(strlen(kntext)
+ + 1,
+ sizeof(char));
+ if (knlval.string == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+ strcpy(knlval.string, kntext);
+ if (keynote_lex_add(knlval.string,
+ LEXTYPE_CHAR) ==
+ -1)
+ return -1;
+ return VARIABLE;
+ }
+"$" return DEREF;
+<ACTIONSTRING>"@" return OPENNUM;
+<ACTIONSTRING>"&" return OPENFLT;
+<ACTIONSTRING>{flt} {
+ knlval.doubval = atof(kntext);
+ return FLOAT;
+ }
+<KEYNOTEVERSION>{number} {
+ if (keynote_exceptionflag ||
+ keynote_donteval)
+ {
+ knlval.string = (char *) NULL;
+ return STRING;
+ }
+
+ knlval.string = calloc(strlen(kntext) + 1,
+ sizeof(char));
+ if (knlval.string == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+ strcpy(knlval.string, kntext);
+ if (keynote_lex_add(knlval.string,
+ LEXTYPE_CHAR) == -1)
+ return -1;
+ return STRING;
+ }
+<ACTIONSTRING>{number} {
+ knlval.intval = atoi(kntext);
+ return NUM;
+ }
+{litstring} {
+ if (keynote_exceptionflag ||
+ keynote_donteval)
+ {
+ knlval.string = (char *) NULL;
+ return STRING;
+ }
+
+ knlval.string = calloc(strlen(kntext) - 1,
+ sizeof(char));
+ if (knlval.string == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ mystrncpy(knlval.string, kntext + 1,
+ strlen(kntext) - 2);
+
+ if (keynote_lex_add(knlval.string,
+ LEXTYPE_CHAR) == -1)
+ return -1;
+ return STRING;
+ }
+[ \t\n]
+. { keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+%%
+
+/*
+ * Zap everything.
+ */
+static void
+keynote_lex_zap(void)
+{
+ int i;
+
+ if (keynote_lex_counter == 0)
+ return;
+
+ for (i = 0; i < keynote_max_lex_list; i++)
+ if (keynote_lex_list[i].lex_s != (void *) NULL)
+ {
+ switch (keynote_lex_list[i].lex_type)
+ {
+ case LEXTYPE_CHAR:
+ free(keynote_lex_list[i].lex_s);
+ break;
+ }
+
+ keynote_lex_counter--;
+ keynote_lex_list[i].lex_s = (void *) NULL;
+ keynote_lex_list[i].lex_type = 0;
+ }
+}
+
+/*
+ * Initialize.
+ */
+static int
+keynote_lex_init(void)
+{
+ if (keynote_lex_list != (struct lex_list *) NULL)
+ memset(keynote_lex_list, 0,
+ keynote_max_lex_list * sizeof(struct lex_list));
+ else
+ {
+ keynote_lex_list = (struct lex_list *) calloc(keynote_max_lex_list,
+ sizeof(struct lex_list));
+ if (keynote_lex_list == (struct lex_list *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+ }
+
+ return RESULT_TRUE;
+}
+
+/*
+ * Add the string in a list of allocated but "dangling" memory references.
+ * If out of memory, free the string and return -1 (and set keynote_errno).
+ */
+int
+keynote_lex_add(void *s, int type)
+{
+ struct lex_list *p;
+ int i;
+
+ if (s == (void *) NULL)
+ return RESULT_TRUE;
+
+ for (i = 0; i < keynote_max_lex_list; i++)
+ if (keynote_lex_list[i].lex_s == (void *) NULL)
+ {
+ keynote_lex_list[i].lex_s = (void *) s;
+ keynote_lex_list[i].lex_type = type;
+ keynote_lex_counter++;
+ return RESULT_TRUE;
+ }
+
+ /* Not enough space, increase the size of the array */
+ keynote_max_lex_list *= 2;
+
+ p = (struct lex_list *) realloc(keynote_lex_list,
+ keynote_max_lex_list *
+ sizeof(struct lex_list));
+ if (p == (struct lex_list *) NULL)
+ {
+ switch (type)
+ {
+ case LEXTYPE_CHAR:
+ free(s);
+ break;
+ }
+
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (p != keynote_lex_list)
+ {
+ free(keynote_lex_list);
+ keynote_lex_list = p;
+ }
+
+ keynote_lex_list[i].lex_s = s;
+ keynote_lex_list[i++].lex_type = type;
+ keynote_lex_counter++;
+
+ /* Zero out the rest */
+ memset(&(keynote_lex_list[i]), 0,
+ (keynote_max_lex_list - i) * sizeof(struct lex_list));
+
+ return RESULT_TRUE;
+}
+
+/*
+ * Remove string.
+ */
+void
+keynote_lex_remove(void *s)
+{
+ int i;
+
+ for (i = 0; i < keynote_max_lex_list; i++)
+ if (keynote_lex_list[i].lex_s == s)
+ {
+ memset(&(keynote_lex_list[i]), 0, sizeof(struct lex_list));
+ keynote_lex_counter--;
+ return;
+ }
+}
+
+/*
+ * Return RESULT_TRUE if character is octal digit, RESULT_FALSE otherwise.
+ */
+static int
+is_octal(char c)
+{
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ return RESULT_TRUE;
+
+ default:
+ return RESULT_FALSE;
+ }
+}
+
+/*
+ * Return octal value (non-zero) if argument starts with such a
+ * representation, otherwise 0.
+ */
+static unsigned char
+get_octal(char *s, int len, int *adv)
+{
+ unsigned char res = 0;
+
+ if (*s == '0')
+ {
+ if (len > 0)
+ {
+ if (is_octal(*(s + 1)))
+ {
+ res = *(s + 1) - '0';
+ *adv = 2;
+
+ if (is_octal(*(s + 2)) && (len - 1 > 0))
+ {
+ res = res * 8 + (*(s + 2) - '0');
+ *adv = 3;
+ }
+ }
+ }
+ }
+ else
+ if (is_octal(*s) && (len - 1 > 0)) /* Non-zero leading */
+ {
+ if (is_octal(*(s + 1)) &&
+ is_octal(*(s + 2)))
+ {
+ *adv = 3;
+ res = (((*s) - '0') * 64) +
+ (((*(s + 1)) - '0') * 8) +
+ ((*(s + 2)) - '0');
+ }
+ }
+
+ return res;
+}
+
+/*
+ * Copy at most len characters to string s1 from string s2, taking
+ * care of escaped characters in the process. String s1 is assumed
+ * to have enough space, and be zero'ed.
+ */
+static void
+mystrncpy(char *s1, char *s2, int len)
+{
+ unsigned char c;
+ int advance;
+
+ if (len == 0)
+ return;
+
+ while (len-- > 0)
+ {
+ if (*s2 == '\\')
+ {
+ s2++;
+
+ if (len-- <= 0)
+ break;
+
+ if (*s2 == '\n')
+ {
+ while (isspace(*(++s2)) && (len-- > 0))
+ ;
+ }
+ else
+ if ((c = get_octal(s2, len, &advance)) != 0)
+ {
+ len -= advance - 1;
+ s2 += advance;
+ *s1++ = c;
+ }
+ else
+ if (*s2 == 'n') /* Newline */
+ {
+ *s1++ = '\n';
+ s2++;
+ }
+ else
+ if (*s2 == 't') /* Tab */
+ {
+ *s1++ = '\t';
+ s2++;
+ }
+ else
+ if (*s2 == 'r') /* Linefeed */
+ {
+ *s1++ = '\r';
+ s2++;
+ }
+ else
+ if (*s2 == 'f') /* Formfeed */
+ {
+ *s1++ = '\f';
+ s2++;
+ }
+ else
+ if ((*s1++ = *s2++) == 0)
+ break;
+
+ continue;
+ }
+
+ if ((*s1++ = *s2++) == 0)
+ break;
+ }
+}
+
+/*
+ * Evaluate an assertion, with as->as_result holding the result.
+ * Return RESULT_TRUE if all ok. Also return the result.
+ */
+int
+keynote_evaluate_assertion(struct assertion *as)
+{
+ YY_BUFFER_STATE keynote_bs;
+
+ /* Non-existant Conditions field means highest return value */
+ if (as->as_conditions_s == (char *) NULL)
+ {
+ as->as_result = keynote_current_session->ks_values_num - 1;
+ return RESULT_TRUE;
+ }
+
+ if (keynote_lex_init() != RESULT_TRUE)
+ return -1;
+
+ keynote_used_variable = 0;
+ keynote_init_list = as->as_env; /* Setup the local-init var list */
+
+ keynote_bs = kn_scan_bytes(as->as_conditions_s,
+ as->as_conditions_e - as->as_conditions_s);
+ BEGIN(ACTIONSTRING); /* We're doing conditions-string parsing */
+ first_tok = ACTSTR;
+ as->as_result = 0;
+ keynote_returnvalue = 0;
+
+ switch (knparse())
+ {
+ case 1: /* Fall through */
+ keynote_errno = ERROR_SYNTAX;
+ case -1:
+ as->as_result = 0;
+ break;
+
+ case 0:
+ as->as_result = keynote_returnvalue;
+ break;
+ }
+
+ keynote_env_cleanup(&keynote_temp_list, 1);
+ keynote_lex_zap();
+ kn_delete_buffer(keynote_bs); /* Free the space */
+
+ keynote_used_variable = 0;
+ keynote_returnvalue = 0;
+ keynote_temp_list = (struct environment *) NULL;
+ keynote_init_list = (struct environment *) NULL;
+
+ if (keynote_errno != 0)
+ return -1;
+ else
+ return RESULT_TRUE;
+}
+
+/*
+ * Parse/evaluate a key predicate field.
+ * Store keys in key predicate as keylist in as->as_keylist, if third
+ * argument is true.
+ */
+int
+keynote_parse_keypred(struct assertion *as, int record)
+{
+ YY_BUFFER_STATE keypred_state;
+ int p = 0, err;
+
+ if (as->as_keypred_s == (char *) NULL)
+ return keynote_current_session->ks_values_num - 1;
+
+ if (keynote_lex_init() != RESULT_TRUE)
+ return -1;
+
+ keynote_used_variable = 0;
+ keynote_returnvalue = 0;
+ keynote_justrecord = record; /* Just want the list of keys in predicate */
+ keynote_init_list = as->as_env;
+
+ keypred_state = kn_scan_bytes(as->as_keypred_s,
+ as->as_keypred_e - as->as_keypred_s);
+ BEGIN(KEYPREDICATE);
+ first_tok = KEYPRE;
+
+ err = knparse();
+ if (err != 0)
+ if (keynote_errno == 0)
+ keynote_errno = ERROR_SYNTAX;
+
+ kn_delete_buffer(keypred_state); /* Free memory */
+ keynote_lex_zap();
+ keynote_cleanup_kth();
+
+ keynote_init_list = (struct environment *) NULL;
+ keynote_justrecord = 0;
+ p = keynote_returnvalue;
+ keynote_returnvalue = 0;
+
+ if (record)
+ {
+ if (keynote_errno != 0)
+ {
+ keynote_keylist_free(keynote_keypred_keylist);
+ keynote_keypred_keylist = (struct keylist *) NULL;
+ return -1;
+ }
+ else
+ {
+ /* Mark for re-processing if/when environment changes */
+ if (keynote_used_variable)
+ {
+ keynote_used_variable = 0;
+ as->as_internalflags |= ASSERT_IFLAG_WEIRDLICS;
+ }
+
+ as->as_keylist = keynote_keypred_keylist;
+ keynote_keypred_keylist = (struct keylist *) NULL;
+ return RESULT_TRUE;
+ }
+ }
+ else
+ return p;
+}
+
+/* Evaluate an authorizer or signature field. Return RESULT_TRUE on success.
+ * Store key in as->as_authorizer. Second argument is set only for Authorizer
+ * field parsing.
+ */
+int
+keynote_evaluate_authorizer(struct assertion *as, int flag)
+{
+ YY_BUFFER_STATE authorizer_state;
+ int err;
+
+ if (keynote_lex_init() != RESULT_TRUE)
+ return -1;
+
+ keynote_init_list = as->as_env;
+ keynote_justrecord = 1;
+ keynote_used_variable = 0;
+
+ if ((flag) && (as->as_authorizer != (void *) NULL))
+ {
+ keynote_free_key(as->as_authorizer, as->as_signeralgorithm);
+ as->as_authorizer = (void *) NULL;
+ }
+
+ if (flag)
+ authorizer_state = kn_scan_bytes(as->as_authorizer_string_s,
+ as->as_authorizer_string_e -
+ as->as_authorizer_string_s);
+ else
+ authorizer_state = kn_scan_bytes(as->as_signature_string_s,
+ as->as_signature_string_e -
+ as->as_signature_string_s);
+
+ BEGIN(SIGNERINIT);
+ if (flag)
+ first_tok = SIGNERKEY;
+ else
+ first_tok = SIGNATUREENTRY;
+
+ err = knparse();
+ if ((err != 0) && (keynote_errno == 0))
+ keynote_errno = ERROR_SYNTAX;
+
+ kn_delete_buffer(authorizer_state); /* Free memory */
+ keynote_lex_zap();
+
+ keynote_justrecord = 0;
+ keynote_init_list = (struct environment *) NULL;
+ keynote_returnvalue = 0;
+
+ if (keynote_keypred_keylist != (struct keylist *) NULL)
+ {
+ if (flag)
+ {
+ if (keynote_used_variable)
+ as->as_internalflags |= ASSERT_IFLAG_WEIRDAUTH;
+
+ as->as_authorizer = keynote_keypred_keylist->key_key;
+ as->as_signeralgorithm = keynote_keypred_keylist->key_alg;
+ }
+ else
+ {
+ if (keynote_used_variable)
+ as->as_internalflags |= ASSERT_IFLAG_WEIRDSIG;
+
+ as->as_signature = keynote_keypred_keylist->key_key;
+ }
+
+ keynote_keypred_keylist->key_key = (char *) NULL;
+ keynote_keylist_free(keynote_keypred_keylist);
+ keynote_keypred_keylist = (struct keylist *) NULL;
+ }
+
+ keynote_used_variable = 0;
+
+ if (keynote_errno != 0)
+ return -1;
+ else
+ return RESULT_TRUE;
+}
+
+/*
+ * Parse a private key.
+ */
+char *
+keynote_get_private_key(char *buf)
+{
+ YY_BUFFER_STATE pkey;
+ char *s;
+ int err;
+
+ if (keynote_lex_init() != RESULT_TRUE)
+ return (char *) NULL;
+
+ keynote_privkey = (char *) NULL;
+ pkey = kn_scan_bytes(buf, strlen(buf));
+ first_tok = PRIVATEKEY;
+ err = knparse();
+ kn_delete_buffer(pkey);
+ keynote_lex_zap();
+
+ if (err != 0)
+ {
+ if (keynote_privkey != (char *) NULL)
+ {
+ free(keynote_privkey);
+ keynote_privkey = (char *) NULL;
+ }
+
+ if (keynote_errno == 0)
+ keynote_errno = ERROR_SYNTAX;
+
+ return (char *) NULL;
+ }
+
+ s = keynote_privkey;
+ keynote_privkey = (char *) NULL;
+ return s;
+}
+
+/*
+ * Parse Local-Constants and KeyNote-Version fields.
+ */
+struct environment *
+keynote_get_envlist(char *buf, char *bufend, int whichfield)
+{
+ struct environment *en = (struct environment *) NULL;
+ YY_BUFFER_STATE localinit_state;
+ int err;
+
+ if (keynote_lex_init() != RESULT_TRUE)
+ return (struct environment *) NULL;
+
+ localinit_state = kn_scan_bytes(buf, bufend - buf);
+ if (whichfield == 0)
+ {
+ BEGIN(LOCALINIT); /* We're doing Local-Constants parsing */
+ first_tok = LOCINI;
+ }
+ else
+ {
+ BEGIN(KEYNOTEVERSION); /* KeyNote-Version parsing */
+ first_tok = KNVERSION;
+ }
+
+ err = knparse();
+ if (err != 0)
+ if (keynote_errno == 0)
+ keynote_errno = ERROR_SYNTAX;
+
+ kn_delete_buffer(localinit_state);
+ keynote_lex_zap();
+
+ if (!whichfield)
+ {
+ if (keynote_errno != 0)
+ keynote_env_cleanup(&keynote_init_list, 1);
+ else
+ en = keynote_init_list;
+
+ keynote_init_list = (struct environment *) NULL;
+ }
+
+ return en;
+}
diff --git a/lib/libkeynote/keynote.y b/lib/libkeynote/keynote.y
new file mode 100644
index 00000000000..ca6c3fbf066
--- /dev/null
+++ b/lib/libkeynote/keynote.y
@@ -0,0 +1,899 @@
+/* $OpenBSD: keynote.y,v 1.1 1999/05/23 22:11:05 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+%union {
+ char *string;
+ double doubval;
+ int intval;
+ int bool;
+};
+%type <bool> stringexp numexp expr floatexp
+%type <intval> NUM KOF numex afterhint notemptyprog
+%type <intval> notemptykeypredicate prog key keyexp keylist
+%type <doubval> FLOAT floatex
+%type <string> STRING VARIABLE str strnotconcat
+%token TRUE FALSE NUM FLOAT STRING VARIABLE
+%token OPENPAREN CLOSEPAREN EQQ COMMA ACTSTR LOCINI KOF KEYPRE KNVERSION
+%token DOTT SIGNERKEY HINT OPENBLOCK CLOSEBLOCK SIGNATUREENTRY PRIVATEKEY
+%token SEMICOLON TRUE FALSE
+%nonassoc EQ NE LT GT LE GE REGEXP
+%left OR
+%left AND
+%right NOT
+%left PLUS MINUS DOTT
+%left MULT DIV MOD
+%left EXP
+%nonassoc UNARYMINUS DEREF OPENNUM OPENFLT
+%start grammarswitch
+%{
+#include <sys/types.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <regex.h>
+#include "environment.h"
+#include "signature.h"
+
+static int *keynote_kth_array = (int *) NULL;
+static int keylistcount = 0;
+
+static int resolve_assertion(char *);
+static int keynote_init_kth(void);
+static int isfloatstring(char *);
+static int checkexception(int);
+static char *my_lookup(char *);
+static int intpow(int, int);
+static int get_kth(int);
+
+extern int keynote_in_action_authorizers(void *, int);
+extern int knlex();
+
+extern int keynote_exceptionflag, keynote_donteval;
+extern char **keynote_values, *keynote_privkey;
+extern struct keylist *keynote_keypred_keylist;
+extern struct environment *keynote_temp_list;
+extern struct environment *keynote_init_list;
+extern int knlineno, keynote_used_variable;
+
+void knerror(char *);
+%}
+%%
+
+grammarswitch: LOCINI { keynote_exceptionflag = keynote_donteval = 0; }
+ localinit
+ | ACTSTR { keynote_exceptionflag = keynote_donteval = 0; } program
+ | KEYPRE { keynote_exceptionflag = keynote_donteval = 0; }
+ keypredicate
+ | SIGNERKEY { keynote_exceptionflag = keynote_donteval = 0; } key
+ | SIGNATUREENTRY { keynote_exceptionflag = keynote_donteval = 0; }
+ key
+ | KNVERSION { keynote_exceptionflag = keynote_donteval = 0; }
+ STRING { keynote_lex_remove($3);
+ if (strcmp($3, KEYNOTE_VERSION_STRING))
+ keynote_errno = ERROR_SYNTAX;
+ free($3);
+ }
+ | PRIVATEKEY { keynote_exceptionflag = keynote_donteval = 0; }
+ STRING { keynote_lex_remove($3);
+ keynote_privkey = $3;
+ }
+
+keypredicate: /* Nothing */ { keynote_returnvalue = 0;
+ return 0;
+ }
+ | notemptykeypredicate { keynote_returnvalue = $1;
+ return 0;
+ }
+
+notemptykeypredicate: key { $$ = $1; }
+ | keyexp { $$ = $1; }
+
+keyexp: notemptykeypredicate AND { if (($1 == 0) && !keynote_justrecord)
+ keynote_donteval = 1;
+ } notemptykeypredicate
+ { if ($1 > $4)
+ $$ = $4;
+ else
+ $$ = $1;
+ keynote_donteval = 0;
+ } /* Min */
+ | notemptykeypredicate OR { if (($1 == (keynote_current_session->ks_values_num - 1)) && !keynote_justrecord)
+ keynote_donteval = 1;
+ } notemptykeypredicate
+ { if ($1 >= $4)
+ $$ = $1;
+ else
+ $$ = $4;
+ keynote_donteval = 0;
+ } /* Max */
+ | OPENPAREN keyexp CLOSEPAREN { $$ = $2; }
+ | KOF { keylistcount = 0; } OPENPAREN {
+ if (!keynote_justrecord && !keynote_donteval)
+ if (keynote_init_kth() == -1)
+ return -1;
+ } keylist CLOSEPAREN
+ {
+ if (keylistcount < $1)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ if (!keynote_justrecord && !keynote_donteval)
+ $$ = get_kth($1);
+ else
+ $$ = 0;
+ } /* K-th */
+
+keylist: key
+ { /* Don't do anything if we're just recording */
+ if (!keynote_justrecord && !keynote_donteval)
+ if (($1 < keynote_current_session->ks_values_num) && ($1 >= 0))
+ keynote_kth_array[$1]++;
+
+ keylistcount++;
+ }
+ | key COMMA keylist
+ { /* Don't do anything if we're just recording */
+ if (!keynote_justrecord && !keynote_donteval)
+ if (($1 < keynote_current_session->ks_values_num) && ($1 >= 0))
+ keynote_kth_array[$1]++;
+
+ keylistcount++;
+ }
+
+key: str {
+ if (keynote_donteval)
+ $$ = 0;
+ else
+ {
+ keynote_lex_remove($1);
+ if (keynote_justrecord)
+ {
+ if (keynote_keylist_add(&keynote_keypred_keylist,
+ $1) == -1)
+ {
+ free($1);
+ return -1;
+ }
+
+ $$ = 0;
+ }
+ else
+ switch (keynote_in_action_authorizers($1, KEYNOTE_ALGORITHM_UNSPEC))
+ {
+ case -1:
+ free($1);
+ return -1;
+
+ case RESULT_TRUE:
+ free($1);
+ $$ = keynote_current_session->ks_values_num -
+ 1;
+ break;
+
+ default:
+ $$ = resolve_assertion($1);
+ free($1);
+ break;
+ }
+ }
+ }
+
+localinit: /* Nothing */
+ | localconstants
+
+localconstants: VARIABLE EQQ STRING
+ {
+ int i;
+
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+
+ /*
+ * Variable names starting with underscores are illegal here.
+ */
+ if ($1[0] == '_')
+ {
+ free($1);
+ free($3);
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ /* If the identifier already exists, report error. */
+ if (keynote_env_lookup($1, &keynote_init_list, 1) != (char *) NULL)
+ {
+ free($1);
+ free($3);
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ i = keynote_env_add($1, $3, &keynote_init_list, 1, 0);
+ free($1);
+ free($3);
+
+ if (i != RESULT_TRUE)
+ return -1;
+ }
+ | VARIABLE EQQ STRING
+ {
+ int i;
+
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+
+ /*
+ * Variable names starting with underscores are illegal here.
+ */
+ if ($1[0] == '_')
+ {
+ free($1);
+ free($3);
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ /* If the identifier already exists, report error. */
+ if (keynote_env_lookup($1, &keynote_init_list, 1) != (char *) NULL)
+ {
+ free($1);
+ free($3);
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ i = keynote_env_add($1, $3, &keynote_init_list, 1, 0);
+ free($1);
+ free($3);
+
+ if (i != RESULT_TRUE)
+ return -1;
+ } localconstants
+
+program: prog {
+ keynote_returnvalue = $1;
+ return 0;
+ }
+
+prog: /* Nada */ { $$ = 0; }
+ | notemptyprog {
+ /*
+ * Cleanup envlist of additions such as
+ * regexp results
+ */
+ keynote_env_cleanup(&keynote_temp_list, 1);
+ } SEMICOLON prog
+ {
+ if ($1 > $4)
+ $$ = $1;
+ else
+ $$ = $4;
+ }
+
+notemptyprog: expr HINT afterhint
+ {
+ if (checkexception($1))
+ $$ = $3;
+ else
+ $$ = 0;
+ }
+ | expr
+ {
+ if (checkexception($1))
+ $$ = keynote_current_session->ks_values_num - 1;
+ else
+ $$ = 0;
+ }
+
+afterhint: str { if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ keynote_lex_remove($1);
+
+ $$ = keynote_retindex($1);
+ if ($$ == -1) /* Invalid return value */
+ $$ = 0;
+
+ free($1);
+ }
+ }
+ | OPENBLOCK prog CLOSEBLOCK { $$ = $2; }
+
+
+expr: OPENPAREN expr CLOSEPAREN { $$ = $2; }
+ | expr AND { if ($1 == 0)
+ keynote_donteval = 1;
+ } expr { $$ = ($1 && $4);
+ keynote_donteval = 0;
+ }
+ | expr OR { if ($1)
+ keynote_donteval = 1;
+ } expr { $$ = ($1 || $4);
+ keynote_donteval = 0;
+ }
+ | NOT expr { $$ = !($2); }
+ | numexp { $$ = $1; }
+ | floatexp { $$ = $1; }
+ | stringexp { $$ = $1; }
+ | TRUE { $$ = 1; }
+ | FALSE { $$ = 0; }
+
+numexp: numex LT numex { $$ = $1 < $3; }
+ | numex GT numex { $$ = $1 > $3; }
+ | numex EQ numex { $$ = $1 == $3; }
+ | numex LE numex { $$ = $1 <= $3; }
+ | numex GE numex { $$ = $1 >= $3; }
+ | numex NE numex { $$ = $1 != $3; }
+
+floatexp: floatex LT floatex { $$ = $1 < $3; }
+ | floatex GT floatex { $$ = $1 > $3; }
+ | floatex LE floatex { $$ = $1 <= $3; }
+ | floatex GE floatex { $$ = $1 >= $3; }
+
+numex: numex PLUS numex { $$ = $1 + $3; }
+ | numex MINUS numex { $$ = $1 - $3; }
+ | numex MULT numex { $$ = $1 * $3; }
+ | numex DIV numex { if ($3 == 0)
+ {
+ if (!keynote_donteval)
+ keynote_exceptionflag = 1;
+ }
+ else
+ $$ = ($1 / $3);
+ }
+ | numex MOD numex { if ($3 == 0)
+ {
+ if (!keynote_donteval)
+ keynote_exceptionflag = 1;
+ }
+ else
+ $$ = $1 % $3;
+ }
+ | numex EXP numex { $$ = intpow($1, $3); }
+ | MINUS numex %prec UNARYMINUS { $$ = -($2); }
+ | OPENPAREN numex CLOSEPAREN { $$ = $2; }
+ | NUM { $$ = $1; }
+ | OPENNUM strnotconcat { if (keynote_exceptionflag ||
+ keynote_donteval)
+ $$ = 0;
+ else
+ {
+ keynote_lex_remove($2);
+
+ if (!isfloatstring($2))
+ $$ = 0;
+ else
+ $$ = (int) floor(atof($2));
+ free($2);
+ }
+ }
+
+floatex: floatex PLUS floatex { $$ = ($1 + $3); }
+ | floatex MINUS floatex { $$ = ($1 - $3); }
+ | floatex MULT floatex { $$ = ($1 * $3); }
+ | floatex DIV floatex { if ($3 == 0)
+ {
+ if (!keynote_donteval)
+ keynote_exceptionflag = 1;
+ }
+ else
+ $$ = ($1 / $3);
+ }
+ | floatex EXP floatex { if (!keynote_exceptionflag &&
+ !keynote_donteval)
+ $$ = pow($1, $3);
+ }
+ | MINUS floatex %prec UNARYMINUS { $$ = -($2); }
+ | OPENPAREN floatex CLOSEPAREN { $$ = $2; }
+ | FLOAT { $$ = $1; }
+ | OPENFLT strnotconcat {
+ if (keynote_exceptionflag ||
+ keynote_donteval)
+ $$ = 0.0;
+ else
+ {
+ keynote_lex_remove($2);
+
+ if (!isfloatstring($2))
+ $$ = 0.0;
+ else
+ $$ = atof($2);
+ free($2);
+ }
+ }
+
+stringexp: str EQ str {
+ if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ $$ = strcmp($1, $3) == 0 ? 1 : 0;
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+ free($1);
+ free($3);
+ }
+ }
+ | str NE str {
+ if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ $$ = strcmp($1, $3) != 0 ? 1 : 0;
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+ free($1);
+ free($3);
+ }
+ }
+ | str LT str {
+ if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ $$ = strcmp($1, $3) < 0 ? 1 : 0;
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+ free($1);
+ free($3);
+ }
+ }
+ | str GT str {
+ if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ $$ = strcmp($1, $3) > 0 ? 1 : 0;
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+ free($1);
+ free($3);
+ }
+ }
+ | str LE str {
+ if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ $$ = strcmp($1, $3) <= 0 ? 1 : 0;
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+ free($1);
+ free($3);
+ }
+ }
+ | str GE str {
+ if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ $$ = strcmp($1, $3) >= 0 ? 1 : 0;
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+ free($1);
+ free($3);
+ }
+ }
+ | str REGEXP str
+ {
+ regmatch_t pmatch[32];
+ char grp[4], *gr;
+ regex_t preg;
+ int i;
+
+ if (keynote_exceptionflag || keynote_donteval)
+ $$ = 0;
+ else
+ {
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+
+ memset(pmatch, 0, sizeof(pmatch));
+ memset(grp, 0, sizeof(grp));
+
+ if (regcomp(&preg, $3, REG_EXTENDED))
+ {
+ free($1);
+ free($3);
+ keynote_exceptionflag = 1;
+ }
+ else
+ {
+ /* Clean-up residuals from previous regexps */
+ keynote_env_cleanup(&keynote_temp_list, 1);
+
+ free($3);
+ i = regexec(&preg, $1, 32, pmatch, 0);
+ $$ = (i == 0 ? 1 : 0);
+ if (i == 0)
+ {
+#ifdef NO_SNPRINTF
+ sprintf(grp, "%d", preg.re_nsub);
+#else /* NO_SNPRINTF */
+ snprintf(grp, 3, "%d", preg.re_nsub);
+#endif /* NO_SNPRINTF */
+ if (keynote_env_add("_0", grp, &keynote_temp_list,
+ 1, 0) != RESULT_TRUE)
+ {
+ free($1);
+ regfree(&preg);
+ return -1;
+ }
+
+ for (i = 1; i < 32 && pmatch[i].rm_so != -1; i++)
+ {
+ gr = calloc(pmatch[i].rm_eo - pmatch[i].rm_so +
+ 1, sizeof(char));
+ if (gr == (char *) NULL)
+ {
+ free($1);
+ regfree(&preg);
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ strncpy(gr, $1 + pmatch[i].rm_so,
+ pmatch[i].rm_eo - pmatch[i].rm_so);
+ gr[pmatch[i].rm_eo - pmatch[i].rm_so] = '\0';
+#ifdef NO_SNPRINTF
+ sprintf(grp, "_%d", i);
+#else /* NO_SNPRINTF */
+ snprintf(grp, 3, "_%d", i);
+#endif /* NO_SNPRINTF */
+ if (keynote_env_add(grp, gr, &keynote_temp_list,
+ 1, 0) == -1)
+ {
+ free($1);
+ regfree(&preg);
+ free(gr);
+ return -1;
+ }
+ else
+ free(gr);
+ }
+ }
+
+ regfree(&preg);
+ free($1);
+ }
+ }
+ }
+
+str: str DOTT str { if (keynote_exceptionflag || keynote_donteval)
+ $$ = (char *) NULL;
+ else
+ {
+ $$ = calloc(strlen($1) + strlen($3) + 1,
+ sizeof(char));
+ keynote_lex_remove($1);
+ keynote_lex_remove($3);
+ if ($$ == (char *) NULL)
+ {
+ free($1);
+ free($3);
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ strcpy($$, $1);
+ strcpy($$ + strlen($1), $3);
+ free($1);
+ free($3);
+ if (keynote_lex_add($$, LEXTYPE_CHAR) == -1)
+ return -1;
+ }
+ }
+ | strnotconcat { $$ = $1; }
+
+strnotconcat: STRING { $$ = $1; }
+ | OPENPAREN str CLOSEPAREN { $$ = $2; }
+ | VARIABLE { if (keynote_exceptionflag || keynote_donteval)
+ $$ = (char *) NULL;
+ else
+ {
+ $$ = my_lookup($1);
+ keynote_lex_remove($1);
+ free($1);
+ if ($$ == (char *) NULL)
+ {
+ if (keynote_errno)
+ return -1;
+ $$ = strdup("");
+ }
+ else
+ $$ = strdup($$);
+
+ if ($$ == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (keynote_lex_add($$, LEXTYPE_CHAR) == -1)
+ return -1;
+ }
+ }
+ | DEREF str { if (keynote_exceptionflag || keynote_donteval)
+ $$ = (char *) NULL;
+ else
+ {
+ $$ = my_lookup($2);
+ keynote_lex_remove($2);
+ free($2);
+ if ($$ == (char *) NULL)
+ {
+ if (keynote_errno)
+ return -1;
+ $$ = strdup("");
+ }
+ else
+ $$ = strdup($$);
+
+ if ($$ == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (keynote_lex_add($$, LEXTYPE_CHAR) == -1)
+ return -1;
+ }
+ }
+%%
+
+/*
+ * Find all assertions signed by s and give us the one with the highest
+ * return value.
+ */
+static int
+resolve_assertion(char *s)
+{
+ int i, alg = KEYNOTE_ALGORITHM_NONE, p = 0;
+ void *key = (void *) s;
+ struct assertion *as;
+ struct keylist *kl;
+
+ kl = keynote_keylist_find(keynote_current_assertion->as_keylist, s);
+ if (kl != (struct keylist *) NULL)
+ {
+ alg = kl->key_alg;
+ key = kl->key_key;
+ }
+
+ for (i = 0;; i++)
+ {
+ as = keynote_find_assertion(key, i, alg);
+ if (as == (struct assertion *) NULL) /* Gone through all of them */
+ return p;
+
+ if (as->as_kresult == KRESULT_DONE)
+ if (p < as->as_result)
+ p = as->as_result;
+
+ /* Short circuit if we find an assertion with maximum return value */
+ if (p == (keynote_current_session->ks_values_num - 1))
+ return p;
+ }
+
+ return 0;
+}
+
+/*
+ * Environment variable lookup.
+ */
+static char *
+my_lookup(char *s)
+{
+ struct keynote_session *ks = keynote_current_session;
+ char *ret;
+
+ if (!strcmp(s, "_MIN_TRUST"))
+ {
+ keynote_used_variable = 1;
+ return ks->ks_values[0];
+ }
+ else
+ {
+ if (!strcmp(s, "_MAX_TRUST"))
+ {
+ keynote_used_variable = 1;
+ return ks->ks_values[ks->ks_values_num - 1];
+ }
+ else
+ {
+ if (!strcmp(s, "_VALUES"))
+ {
+ keynote_used_variable = 1;
+ return keynote_env_lookup("_VALUES", ks->ks_env_table,
+ HASHTABLESIZE);
+ }
+ else
+ {
+ if (!strcmp(s, "_ACTION_AUTHORIZERS"))
+ {
+ keynote_used_variable = 1;
+ return keynote_env_lookup("_ACTION_AUTHORIZERS",
+ ks->ks_env_table, HASHTABLESIZE);
+ }
+ }
+ }
+ }
+
+ /* Temporary list (regexp results) */
+ ret = keynote_env_lookup(s, &keynote_temp_list, 1);
+ if (ret != (char *) NULL)
+ return ret;
+ else
+ if (keynote_errno != 0)
+ return (char *) NULL;
+
+ /* Local-Constants */
+ ret = keynote_env_lookup(s, &keynote_init_list, 1);
+ if (ret != (char *) NULL)
+ return ret;
+ else
+ if (keynote_errno != 0)
+ return (char *) NULL;
+
+ keynote_used_variable = 1;
+
+ /* Action environment */
+ ret = keynote_env_lookup(s, ks->ks_env_table, HASHTABLESIZE);
+ if (ret != (char *) NULL)
+ return ret;
+ else
+ if (keynote_errno != 0)
+ return (char *) NULL;
+
+ /* Regex table */
+ return keynote_env_lookup(s, &(ks->ks_env_regex), 1);
+}
+
+/*
+ * If we had an exception, the boolean expression should return false.
+ * Otherwise, return the result of the expression (the argument).
+ */
+static int
+checkexception(int i)
+{
+ if (keynote_exceptionflag)
+ {
+ keynote_exceptionflag = 0;
+ return 0;
+ }
+ else
+ return i;
+}
+
+
+/*
+ * Integer exponentation -- copied from Schneier's AC2, page 244.
+ */
+static int
+intpow(int x, int y)
+{
+ int s = 1;
+
+ /*
+ * x^y with y < 0 is equivalent to 1/(x^y), which for
+ * integer arithmetic is 0.
+ */
+ if (y < 0)
+ return 0;
+
+ while (y)
+ {
+ if (y & 1)
+ s *= x;
+
+ y >>= 1;
+ x *= x;
+ }
+
+ return s;
+}
+
+/*
+ * Check whether the string is a floating point number.
+ */
+static int
+isfloatstring(char *s)
+{
+ int i, point = 0;
+
+ for (i = strlen(s) - 1; i >= 0; i--)
+ if (!isdigit(s[i]))
+ {
+ if (s[i] == '.')
+ {
+ if (point == 1)
+ return 0;
+ else
+ point = 1;
+ }
+ else
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Initialize array for threshold search.
+ */
+static int
+keynote_init_kth(void)
+{
+ int i = keynote_current_session->ks_values_num;
+
+ if (i == -1)
+ return -1;
+
+ keynote_kth_array = (int *) calloc(i, sizeof(int));
+ if (keynote_kth_array == (int *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ return RESULT_TRUE;
+}
+
+/*
+ * Get the k-th best return value.
+ */
+static int
+get_kth(int k)
+{
+ int i;
+
+ for (i = keynote_current_session->ks_values_num - 1; i >= 0; i--)
+ {
+ k -= keynote_kth_array[i];
+
+ if (k <= 0)
+ return i;
+ }
+
+ return 0;
+}
+
+/*
+ * Cleanup array.
+ */
+void
+keynote_cleanup_kth(void)
+{
+ if (keynote_kth_array != (int *) NULL)
+ {
+ free(keynote_kth_array);
+ keynote_kth_array = (int *) NULL;
+ }
+}
+
+void
+knerror(char *s)
+{}
diff --git a/lib/libkeynote/man/keynote-keygen.1 b/lib/libkeynote/man/keynote-keygen.1
new file mode 100644
index 00000000000..845baa984e3
--- /dev/null
+++ b/lib/libkeynote/man/keynote-keygen.1
@@ -0,0 +1,113 @@
+.\" $OpenBSD: keynote-keygen.1,v 1.1 1999/05/23 22:11:07 angelos Exp $
+.\"
+.\" The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.\"
+.\" This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+.\" in April-May 1998
+.\"
+.\" Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+.\"
+.\" Permission to use, copy, and modify this software without fee
+.\" is hereby granted, provided that this entire notice is included in
+.\" all copies of any software which is or includes a copy or
+.\" modification of this software.
+.\" You may use this code under the GNU public license if you so wish. Please
+.\" contribute changes back to the author.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+.\" REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+.\" MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+.\" PURPOSE.
+.\"
+.Dd April 29, 1999
+.Dt keynote-keygen 1
+.Os
+.\" .TH keynote-keygen 1 local
+.Sh NAME
+.Nm keynote-keygen
+.Nd command line tool for generating public/private keys
+.Sh SYNOPSIS
+.Nm keynote-keygen
+.Ar AlgorithmName
+.Ar KeySize
+.Ar PublicKeyFile
+.Ar PrivateKeyFile
+.Op print-offset
+.Op print-length
+.Sh DESCRIPTION
+For details on
+.Nm KeyNote ,
+see the web page
+.Bd -literal -offset indent
+ http://www.cis.upenn.edu/~keynote
+.Ed
+.Pp
+.Nm keynote-keygen
+creates a public/private key of size
+.Fa KeySize ,
+for the algorithm specified by
+.Fa AlgorithmName .
+Typical keysizes are 512, 1024, or 2048 (bits). The minimum key size
+for DSA keys is 512 (bits). Supported
+.Fa AlgorithmName
+identifiers are:
+.Bl -tag -width indent
+.It ``dsa-hex:''
+.It ``dsa-base64:''
+.It ``rsa-hex:''
+.It ``rsa-base64:''
+.El
+.Pp
+Notice that the trailing colon is required.
+The resulting public key is stored in file
+.Fa PublicKeyFile .
+Similarly, the resulting private key is stored in file
+.Fa PrivateKeyFile .
+Either of the filenames can be specified to be ``-'', in which
+case the corresponding key(s) will be printed in standard output.
+.Pp
+The optional parameters
+.Fa print-offset
+and
+.Fa print-length
+specify the offset from the begining of the line where the key
+will be printed, and the number of characters of the key that will
+be printed per line.
+.Fa print-length
+includes
+.Fa AlgorithmName
+for the first line and has to be longer (by at least 2) than
+.Fa AlgorithmName .
+.Fa print-length
+also accounts for the line-continuation character (backslash) at
+the end of each line, and the doublequotes at the begining and end
+of the key encoding. Default values are 12 and 50 respectively.
+.Pp
+.Sh SEE ALSO
+.Xr keynote 3 ,
+.Xr keynote 4 ,
+.Xr keynote-sign 1 ,
+.Xr keynote-sigver 1 ,
+.Xr keynote-verify 1
+.Bl -tag -width "AAAAAAA"
+.It ``The KeyNote Trust-Management System''
+M. Blaze, J. Feigenbaum, A. D. Keromytis,
+Internet Drafts, draft-ietf-trustmgt-keynote-00.txt
+.It ``Decentralized Trust Management''
+M. Blaze, J. Feigenbaum, J. Lacy,
+1996 IEEE Conference on Privacy and Security
+.It ``Compliance-Checking in the PolicyMaker Trust Management System''
+M. Blaze, J. Feigenbaum, M. Strauss,
+1998 Financial Crypto Conference
+.El
+.Sh AUTHOR
+Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.Sh WEB PAGE
+http://www.cis.upenn.edu/~keynote
+.Sh BUGS
+None that we know of.
+If you find any, please report them at
+.Bd -literal -offset indent -compact
+keynote@research.att.com
+.Ed
diff --git a/lib/libkeynote/man/keynote-sign.1 b/lib/libkeynote/man/keynote-sign.1
new file mode 100644
index 00000000000..0ae1bd045e6
--- /dev/null
+++ b/lib/libkeynote/man/keynote-sign.1
@@ -0,0 +1,129 @@
+.\" $OpenBSD: keynote-sign.1,v 1.1 1999/05/23 22:11:07 angelos Exp $
+.\"
+.\" The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.\"
+.\" This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+.\" in April-May 1998
+.\"
+.\" Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+.\"
+.\" Permission to use, copy, and modify this software without fee
+.\" is hereby granted, provided that this entire notice is included in
+.\" all copies of any software which is or includes a copy or
+.\" modification of this software.
+.\" You may use this code under the GNU public license if you so wish. Please
+.\" contribute changes back to the author.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+.\" REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+.\" MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+.\" PURPOSE.
+.\"
+.Dd April 29, 1999
+.Dt keynote-sign 1
+.Os
+.\" .TH keynote-sign 1 local
+.Sh NAME
+.Nm keynote-sign
+.Nd command line tool for signing
+.Xr KeyNote 3
+assertions
+.Sh SYNOPSIS
+.Nm keynote-sign
+.Op Fl v
+.Ar AlgorithmName
+.Ar AssertionFile
+.Ar PrivateKeyFile
+.Sh DESCRIPTION
+For details on
+.Nm KeyNote ,
+see the web page
+.Bd -literal -offset indent
+ http://www.cis.upenn.edu/~keynote
+.Ed
+.Pp
+.Nm keynote-sign
+reads the assertion contained in
+.Fa AssertionFile
+and generates a signature specified by
+.Fa AlgorithmName
+using the private key stored in
+.Fa PrivateKeyFile .
+The private key is expected to be of the form output by
+.Xr keynote-keygen 1 .
+The private key algorithm and the
+.Fa AlgorithmName
+specified as an argument are expected to match. There is no requirement
+for the internal or ASCII encodings to match.
+Valid
+.Fa AlgorithmName
+identifiers are:
+.Bl -tag -width indent
+.It ``sig-dsa-sha1-hex:''
+.It ``sig-dsa-sha1-base64:''
+.It ``sig-rsa-sha1-hex:''
+.It ``sig-rsa-sha1-base64:''
+.It ``sig-rsa-md5-hex:''
+.It ``sig-rsa-md5-base64:''
+.El
+.Pp
+Notice that the trailing colon is required.
+The resulting signature is printed in standard output. This can then
+be added (via cut-and-paste or some script) at the end of the
+assertion, in the
+.Fa Signature
+field.
+.Pp
+The public key corresponding to the private key in
+.Fa PrivateKeyFile
+is expected to already be included in the
+.Fa Authorizer
+field of the assertion, either directly or indirectly (i.e., through
+use of a
+.Fa Local-Init
+attribute). Furthermore, the assertion must have a
+.Fa Signature
+field (even if it is empty), as the signature is computed on
+everything between the
+.Fa KeyNote-Version
+and
+.Fa Signature
+keywords (inclusive), and the
+.Fa AlgorithmName
+string.
+.Pp
+If the
+.Op Fl v
+flag is provided,
+.Nm keynote-sign
+will also verify the newly-created signature using the
+.Fa Authorizer
+field key.
+.Sh SEE ALSO
+.Xr keynote 3 ,
+.Xr keynote 4 ,
+.Xr keynote-keygen 1 ,
+.Xr keynote-sigver 1 ,
+.Xr keynote-verify 1
+.Bl -tag -width "AAAAAAA"
+.It ``The KeyNote Trust-Management System''
+M. Blaze, J. Feigenbaum, A. D. Keromytis,
+Internet Drafts, draft-ietf-trustmgt-keynote-00.txt
+.It ``Decentralized Trust Management''
+M. Blaze, J. Feigenbaum, J. Lacy,
+1996 IEEE Conference on Privacy and Security
+.It ``Compliance-Checking in the PolicyMaker Trust Management System''
+M. Blaze, J. Feigenbaum, M. Strauss,
+1998 Financial Crypto Conference
+.El
+.Sh AUTHOR
+Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.Sh WEB PAGE
+http://www.cis.upenn.edu/~keynote
+.Sh BUGS
+None that we know of.
+If you find any, please report them at
+.Bd -literal -offset indent -compact
+keynote@research.att.com
+.Ed
diff --git a/lib/libkeynote/man/keynote-sigver.1 b/lib/libkeynote/man/keynote-sigver.1
new file mode 100644
index 00000000000..cdbc72b5b8e
--- /dev/null
+++ b/lib/libkeynote/man/keynote-sigver.1
@@ -0,0 +1,73 @@
+.\" $OpenBSD: keynote-sigver.1,v 1.1 1999/05/23 22:11:07 angelos Exp $
+.\"
+.\" The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.\"
+.\" This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+.\" in April-May 1998
+.\"
+.\" Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+.\"
+.\" Permission to use, copy, and modify this software without fee
+.\" is hereby granted, provided that this entire notice is included in
+.\" all copies of any software which is or includes a copy or
+.\" modification of this software.
+.\" You may use this code under the GNU public license if you so wish. Please
+.\" contribute changes back to the author.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+.\" REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+.\" MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+.\" PURPOSE.
+.\"
+.Dd April 29, 1999
+.Dt keynote-sigver 1
+.Os
+.\" .TH keynote-sigver 1 local
+.Sh NAME
+.Nm keynote-sigver
+.Nd command line tool for verifying signed
+.Xr KeyNote 3
+assertions
+.Sh SYNOPSIS
+.Nm keynote-sigver
+.Op AssertionFile
+.Sh DESCRIPTION
+For details on
+.Nm KeyNote ,
+see the web page
+.Bd -literal -offset indent
+ http://www.cis.upenn.edu/~keynote
+.Ed
+.Pp
+.Nm keynote-sigver
+reads the assertion contained in
+.Fa AssertionFile
+and verifies the public key signature on it.
+.Sh SEE ALSO
+.Xr keynote 3 ,
+.Xr keynote 4 ,
+.Xr keynote-keygen 1 ,
+.Xr keynote-sign 1 ,
+.Xr keynote-verify 1
+.Bl -tag -width "AAAAAAA"
+.It ``The KeyNote Trust-Management System''
+M. Blaze, J. Feigenbaum, A. D. Keromytis,
+Internet Drafts, draft-ietf-trustmgt-keynote-00.txt
+.It ``Decentralized Trust Management''
+M. Blaze, J. Feigenbaum, J. Lacy,
+1996 IEEE Conference on Privacy and Security
+.It ``Compliance-Checking in the PolicyMaker Trust Management System''
+M. Blaze, J. Feigenbaum, M. Strauss,
+1998 Financial Crypto Conference
+.El
+.Sh AUTHOR
+Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.Sh WEB PAGE
+http://www.cis.upenn.edu/~keynote
+.Sh BUGS
+None that we know of.
+If you find any, please report them at
+.Bd -literal -offset indent -compact
+keynote@research.att.com
+.Ed
diff --git a/lib/libkeynote/man/keynote-verify.1 b/lib/libkeynote/man/keynote-verify.1
new file mode 100644
index 00000000000..2e390500fba
--- /dev/null
+++ b/lib/libkeynote/man/keynote-verify.1
@@ -0,0 +1,138 @@
+.\" $OpenBSD: keynote-verify.1,v 1.1 1999/05/23 22:11:07 angelos Exp $
+.\"
+.\" The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.\"
+.\" This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+.\" in April-May 1998
+.\"
+.\" Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+.\"
+.\" Permission to use, copy, and modify this software without fee
+.\" is hereby granted, provided that this entire notice is included in
+.\" all copies of any software which is or includes a copy or
+.\" modification of this software.
+.\" You may use this code under the GNU public license if you so wish. Please
+.\" contribute changes back to the author.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+.\" REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+.\" MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+.\" PURPOSE.
+.\"
+.Dd April 29, 1999
+.Dt keynote-verify 1
+.Os
+.\" .TH keynote-verify 1 local
+.Sh NAME
+.Nm keynote-verify
+.Nd command line tool for evaluating
+.Xr KeyNote 3
+assertions
+.Sh SYNOPSIS
+.Nm keynote-verify
+.Op Fl h
+.Op Fl e Ar file
+.Fl l Ar file
+.Fl r Ar retlist
+.Op Fl k Ar file
+.Op Fl l Ar file
+.Op Ar file ...
+.Sh DESCRIPTION
+For details on
+.Nm KeyNote ,
+see the web page
+.Bd -literal -offset indent
+ http://www.cis.upenn.edu/~keynote
+.Ed
+.Pp
+For each operand that names a
+.A file ,
+.Nm keynote-verify
+reads the file and parses the assertions contained therein (one
+assertion per file).
+.Pp
+Files given with the
+.Fl l
+flag are assumed to contain trusted assertions (no signature
+verification is performed, and the
+.Fa Authorizer
+field can contain non-key principals.
+There should be at least one assertion with the
+.Fa POLICY
+keyword in the
+.Fa Authorizer
+field.
+.Pp
+The
+.Fl r
+flag is used to provide a comma-separated list of return values, in
+increasing order of compliance from left to right.
+.Pp
+Files given with the
+.Fl e
+flag are assumed to contain environment variables and their values,
+in the format:
+.Bd -literal -offset indent
+ varname = \"value\"
+.Ed
+.Pp
+.Fa varname
+can begin with any letter (upper or lower case) or number,
+and can contain underscores.
+.Fa value
+is a quoted string, and can contain any character, and escape
+(backslash) processing is performed, as specified in the KeyNote
+draft.
+.Pp
+The remaining options are:
+.Bl -tag -width indent
+.It Fl h
+Print a usage message and exit.
+.It Fl k Ar file
+Add a key from
+.Fa file
+in the action authorizers.
+.El
+.Pp
+Exactly one
+.Fl r
+and least one of each
+.Fl e ,
+.Fl l ,
+and
+.Fl k
+flags should be given per invocation. If no flags are given,
+.Nm keynote-verify
+prints the usage message and exits with error code -1.
+.Pp
+The
+.Nm keynote-verify
+exits with code -1 if there was an error, and 0 on success.
+.Sh SEE ALSO
+.Xr keynote 3 ,
+.Xr keynote 4 ,
+.Xr keynote-keygen 1 ,
+.Xr keynote-sign 1 ,
+.Xr keynote-sigver 1
+.Bl -tag -width "AAAAAAA"
+.It ``The KeyNote Trust-Management System''
+M. Blaze, J. Feigenbaum, A. D. Keromytis,
+Internet Drafts, draft-ietf-trustmgt-keynote-00.txt
+.It ``Decentralized Trust Management''
+M. Blaze, J. Feigenbaum, J. Lacy,
+1996 IEEE Conference on Privacy and Security
+.It ``Compliance-Checking in the PolicyMaker Trust Management System''
+M. Blaze, J. Feigenbaum, M. Strauss,
+1998 Financial Crypto Conference
+.El
+.Sh AUTHOR
+Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.Sh WEB PAGE
+http://www.cis.upenn.edu/~keynote
+.Sh BUGS
+None that we know of.
+If you find any, please report them at
+.Bd -literal -offset indent -compact
+keynote@research.att.com
+.Ed
diff --git a/lib/libkeynote/man/keynote.3 b/lib/libkeynote/man/keynote.3
new file mode 100644
index 00000000000..3575ffc2fe1
--- /dev/null
+++ b/lib/libkeynote/man/keynote.3
@@ -0,0 +1,770 @@
+.\" $OpenBSD: keynote.3,v 1.1 1999/05/23 22:11:07 angelos Exp $
+.\"
+.\" The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.\"
+.\" This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+.\" in April-May 1998
+.\"
+.\" Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+.\"
+.\" Permission to use, copy, and modify this software without fee
+.\" is hereby granted, provided that this entire notice is included in
+.\" all copies of any software which is or includes a copy or
+.\" modification of this software.
+.\" You may use this code under the GNU public license if you so wish. Please
+.\" contribute changes back to the author.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+.\" REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+.\" MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+.\" PURPOSE.
+.\"
+.Dd April 29, 1999
+.Dt KeyNote 3
+.Os
+.\" .TH KeyNote 3 local
+.Sh NAME
+.Nm KeyNote
+.Nd A Trust-Management System Library
+.Sh SYNOPSIS
+.Fd #include <keynote.h>
+.Bd -literal
+
+struct environment
+{
+ char *env_name;
+ char *env_value;
+ int env_flags;
+ regex_t env_regex;
+ struct environment *env_next;
+};
+
+struct keynote_deckey
+{
+ int dec_algorithm;
+ void *dec_key;
+};
+
+struct keynote_binary
+{
+ int bn_len;
+ char *bn_key;
+};
+.Ed
+.Ft int
+.Fd keynote_errno;
+.Ft int
+.Fn kn_init "void"
+.Ft int
+.Fn kn_add_assertion "int sessid" "char *assertion" "int len" "int flags"
+.Ft int
+.Fn kn_remove_assertion "int sessid" "int assertid"
+.Ft int
+.Fn kn_add_action "int sessid" "char *name" "char *value" "int flags"
+.Ft int
+.Fn kn_remove_action "int sessid" "char *name"
+.Ft int
+.Fn kn_add_authorizer "int sessid" "char *principal"
+.Ft int
+.Fn kn_remove_authorizer "int sessid" "char *principal"
+.Ft int
+.Fn kn_do_query "int sessid" "char **returnvalues" "int numvalues"
+.Ft int
+.Fn kn_get_failed "int sessid" "int type" "int seq"
+.Ft int
+.Fn kn_close "int sessid"
+.Ft int
+.Fn kn_query "struct environment *env" "char **returnvalues, int numvalues" "char **trusted, int *trustedlen, int numtrusted" "char **untrusted, int *untrustedlen, int numuntrusted" "char **authorizers, int numauthauthorizers"
+.Ft char **
+.Fn kn_read_asserts "char *array" "int arraylen" "int *numassertions"
+.Ft int
+.Fn kn_encode_base64 "unsigned char const *src" "unsigned int srclen" "char *dst" "unsigned int dstlen"
+.Ft int
+.Fn kn_decode_base64 "char const *src" "unsigned char *dst" "unsigned int dstlen"
+.Ft int
+.Fn kn_encode_hex "unsigned char *src" "char **dst" "int srclen"
+.Ft int
+.Fn kn_decode_hex "char *src" "char **dst"
+.Ft char *
+.Fn kn_encode_key "struct keynote_deckey *dc" "int iencoding" "int encoding" "int keytype"
+.Ft int
+.Fn kn_decode_key "struct keynote_deckey *dc" "char *key" "int keytype"
+.Ft char *
+.Fn kn_sign_assertion "char *assertion" "int len" "char *key" "char *algorithm" "int vflag"
+.Ft int
+.Fn kn_verify_assertion "char *assertion" "int len"
+.Fd Link options: -lkeynote -lm -lcrypto
+.Sh DESCRIPTION
+For details on
+.Nm KeyNote ,
+see the web page
+.Bd -literal -offset indent
+ http://www.cis.upenn.edu/~keynote
+.Ed
+.Pp
+.Va keynote_errno
+contains an error code if some library call failed. Failed calls
+return -1 (if their return value is integer), or
+.Dv NULL
+(if their return value is a pointer) and set
+.Va keynote_errno .
+The defined error codes are:
+.Bl -tag -width "ERROR_NOTFOUND" -offset indent
+.It Li ERROR_MEMORY
+Some memory allocation or usage error was encountered.
+.It Li ERROR_SYNTAX
+Some syntactic or logical error was encountered.
+.It Li ERROR_NOTFOUND
+One of the arguments referred to a nonexistent structure or entry.
+.El
+.Pp
+If no errors were encountered,
+.Va keynote_errno
+will be set to 0. This variable should be reset to 0 if an error was
+encountered, prior to calling other library routines.
+.Pp
+The main interface to
+.Nm KeyNote
+is centered around the concept of a session. A session describes a
+collection of policies, assertions, action authorizers, return values,
+and action attributes that the
+.Nm KeyNote
+system uses to evaluate a query. Information is not shared between
+sessions. Policies, credentials, action authorizers, and action
+attributes can be added or deleted at any point during the lifetime of
+a session. Furthermore, an application can discover which assertions
+failed to be evaluated, and in what way, during a query.
+.Pp
+For those applications that only need to do a simple query, there
+exists a single call that takes as arguments all the necessary
+information and performs all the necessary steps. This is essentially
+a wrapper that calls the session API functions as necessary.
+.Pp
+Finally, there exist functions for doing ASCII to hexadecimal and
+Base64 encoding (and vice versa), for encoding/decoding keys between
+ASCII and binary formats, and for signing and verifying assertions.
+.Pp
+The description of all
+.Nm KeyNote
+library functions follows.
+.Pp
+.Fn kn_init
+creates a new
+.Nm KeyNote
+session, and performs any necessary initializations. On success, this
+function returns the new session ID, which is used by all subsequent
+calls with a
+.Fa sessid
+argument.
+On failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_MEMORY .
+.Pp
+.Fn kn_add_assertion
+adds the assertion pointed to by the array
+.Fa assertion ,
+of length
+.Fa len
+in the session identified by
+.Fa sessid .
+The first argument can be discarded after the call to this function.
+The following flags are defined:
+.Bl -tag -width ASSERT_FLAG_LOCAL -offset indent
+.It ASSERT_FLAG_LOCAL
+Mark this assertion as ultimately trusted.
+Trusted assertions need not be signed, and the
+.Fa Authorizer
+and
+.Fa Licensees
+fields can have non-key entries.
+.El
+.Pp
+At least one (trusted) assertion should have
+.Dv POLICY
+as the
+.Fa Authorizer .
+On success, this function will return an assertion ID which can be
+used to remove the assertion from the session, by using
+.Xr kn_remove_assertion 3 .
+On failure, -1 is returned, and
+.Va keynote_errno
+is set to
+.Er ERROR_NOTFOUND
+if the session was not found,
+.Er ERROR_SYNTAX
+if the assertion was syntactically incorrect, or
+.Er ERROR_MEMORY
+if necessary memory could not be allocated.
+.Pp
+.Fn kn_remove_assertion
+removes the assertion identified by
+.Fa assertid
+from the session identified by
+.Fa sessid .
+On success, this function returns 0. On failure, it returns -1 and
+sets
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND .
+.Pp
+.Fn kn_add_action
+inserts the variable
+.Fa name
+in the action environment of session
+.Fa sessid ,
+with the value
+.Fa value .
+The same attribute may be added more than once, but only the last
+instance will be used (memory resources are consumed however).
+.Pp
+The
+.Fa flags
+specified are formed by or'ing the following values:
+.Bl -tag -width ENVIRONMENT_FLAG_REGEX -offset indent
+.It ENVIRONMENT_FLAG_FUNC
+In this case,
+.Fa value
+is a pointer to a function that takes as argument a string and returns
+a string. This is used to implement callbacks for getting action
+attribute values. The argument passed to such a callback function is a
+string identifying the action attribute whose value is requested, and
+should return a pointer to string containing that value (this pointer
+will not be freed by the library), the empty string if the value was
+not found, or a
+.Dv NULL
+to indicate an error (and may set
+.Va keynote_errno
+appropriately). Prior to first use (currently, at the time the
+attribute is added to the session environment), such functions are
+called with
+.Dv KEYNOTE_CALLBACK_INITIALIZE
+as the argument (defined in keynote.h) so that they can
+perform any special initializations. Furthermore, when the
+session is deleted, all such functions will be called with
+.Dv KEYNOTE_CALLBACK_CLEANUP
+to perform any special cleanup (such as free any allocated memory). A
+function may be called with either of these arguments more than once,
+if it has been defined as the callback function for more than one
+attribute.
+.It ENVIRONMENT_FLAG_REGEX
+In this case,
+.Fa name
+is a regular expression that may match more than one attribute.
+In case of conflict between a regular expression and a ``simple''
+attribute, the latter will be given priority. In case of conflict
+between two regular expression attributes, the one added later will be
+given priority. A callback function should never change the current
+.Nm KeyNote
+session, start/invoke/operate on another session, or call one of the
+session-API functions.
+.El
+.Pp
+The combination of the two flags may be used to specify callback
+functions that handle large sets of attributes (even to the extent of
+having one callback function handling all attribute references). This
+is particularly useful when the action attribute set is particularly
+large.
+.Pp
+On success,
+.Xr keynote_add_action 3
+returns 0. On failure, it returns -1 and sets
+.Va keynote_errno to
+.Er ERROR_NOTFOUND
+if the session was not found,
+.Er ERROR_SYNTAX
+if the
+.Fa name
+was invalid (e.g., started with an underscore character) or was
+.Dv NULL ,
+or
+.Er ERROR_MEMORY
+if necessary memory could not be allocated.
+.Pp
+.Fn kn_remove_action
+removes action attribute
+.Fa name
+from the environment of session
+.Fa sessid .
+Notice that if more than one instances of
+.Fa name
+exist, only the one added last will be deleted.
+On success, this function returns 0. On failure, it returns -1 and
+.Va keynote_errno
+is set to
+.Er ERROR_NOTFOUND
+if the session or the attribute were not found, or
+.Er ERROR_SYNTAX
+if the name was invalid. If the attribute value was a callback, that
+function will be called with the define
+.Dv KEYNOTE_CALLBACK_CLEANUP
+as the argument.
+.Pp
+.Fn kn_add_authorizer
+adds the principal pointed to by
+.Fa principal
+to the action authorizers list of session
+.Fa sessid .
+The principal is typically an ASCII-encoded key. On success, this
+function will return 0. On failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND
+if the session was not found,
+.Er ERROR_SYNTAX
+if the encoding was invalid, or
+.Er ERROR_MEMORY
+if necessary memory could not be allocated.
+.Pp
+.Fn kn_remove_authorizer
+removes
+.Fa principal
+from the action authorizer list of session
+.Fa sessid .
+On success, this function returns 0. On failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND
+if the session was not found.
+.Pp
+.Fn kn_do_query
+evaluates the request based on the assertions, action attributes, and
+action authorizers added to session
+.Fa sessid .
+.Fa returnvalues
+is an ordered array of strings that contain the return values. The
+lowest-ordered return value is contained in
+.Fa returnvalues[0] ,
+and the highest-ordered value is
+.Fa returnvalues[numvalues - 1] .
+If
+.Fa returnvalues
+is
+.Dv NULL ,
+the
+.Fa returnvalues
+from the previous call to
+.Xr kn_do_query 3
+will be used. The programmer SHOULD NOT free
+.Fa returnvalues
+after the call to
+.Xr kn_do_query 3
+if this feature is used, as the array is not replicated internally.
+On success, this function returns an index into the
+.Fa returnvalues
+array. On failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND
+if the session was not found or the authorizers list was empty,
+.Er ERROR_SYNTAX
+if no
+.Fa returnvalues
+have been specified, or
+.Er ERROR_MEMORY
+if necessary memory could not be allocated.
+.Pp
+.Fn kn_get_failed
+returns the assertion ID of the
+.Fa num'th
+assertion (starting from zero) in session
+.Fa sessid
+that was somehow invalid during evaluation. This function is typically
+called after
+.Xr kn_do_query 3
+is used to evaluate a request.
+.Fa type
+specifies the type of failure the application is interested in. It can
+be set to:
+.Bl -tag -width KEYNOTE_ERROR_SIGNATURE -offset indent
+.It KEYNOTE_ERROR_ANY
+to indicate interest in any error.
+.It KEYNOTE_ERROR_SYNTAX
+for syntactic or semantic errors.
+.It KEYNOTE_ERROR_MEMORY
+for memory-related problems.
+.It KEYNOTE_ERROR_SIGNATURE
+if the assertion could be be cryptographically verified.
+.El
+.Pp
+These values are defined in keynote.h. An application can then delete
+the offending assertion using
+.Xr kn_remove_assertion 3 .
+For example, to remove all assertion whose signature failed, an
+application could do something like:
+.Bd -literal
+ while ((assertid = kn_get_failed(sessid, KEYNOTE_ERROR_SIGNATURE, 0)
+ != -1)
+ kn_remove_assertion(sessid, assertid);
+.Ed
+.Pp
+On success,
+.Xr kn_get_failed 3
+returns an assertion ID. On failure, or when no assertion matching the
+given criteria is found, it returns -1 and set
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND .
+.Pp
+.Fn kn_close
+closes session
+.Fa sessid
+and frees all related resources, deleting action attributes, action
+authorizers, and assertions. On success, this function returns 0. On
+failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND
+if the session was not found.
+.Pp
+.Fn kn_read_asserts
+parses the string
+.Fa array
+of length
+.Fa arraylen
+and returns an array of strings containing the assertions found in
+.Fa array .
+.Fa numassertions
+contains the number of assertions (and thus strings in the returned
+array) found in
+.Fa array .
+On failure, this function returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_MEMORY
+if necessary memory could not be allocated, or
+.Er ERROR_SYNTAX
+if
+.Fa array
+was
+.Dv NULL .
+.Pp
+.Fn kn_query
+takes as arguments a list of action attributes in
+.Fa env ,
+a list of return values in
+.Fa returnvalues
+(the number of returnvalues in indicated by
+.Fa numvalues ),
+a number (
+.Fa numtrusted )
+of locally-trusted assertions in
+.Fa trusted
+(the length of each assertion is given by the respective element of
+.Fa trustedlen ),
+a number (
+.Fa numuntrusted )
+of assertions that need to be cryptographically verified in
+.Fa untrusted
+(the length of each assertion is given by the respective element of
+.Fa untrustedlen ),
+and a number (
+.Fa numauthorizers )
+of action authorizers in
+.Fa authorizers .
+.Fa env
+is a linked list of
+.Fa struct environment
+structures. The
+.Fa env_name ,
+.Fa env_value ,
+and
+.Fa env_flags
+fields correspond to the
+.Fa name ,
+.Fa value ,
+and
+.Fa flags
+arguments to
+.Xr kn_add_assertion 3
+respectively.
+.Fa env_regex
+is not used. On success, this function returns an index in
+.Fa returnvalues
+indicating the returned value to the query. On failure, it returns -1
+and sets
+.Va keynote_errno
+to the same values as
+.Xr kn_do_query 3 .
+.Pp
+.Fn kn_encode_base64
+converts the data of length
+.Fa srclen
+contained in
+.Fa src
+in Base64 encoding and stores them in
+.Fa dst
+which is of length
+.Fa dstlen .
+The actual length of the encoding stored in
+.Fa dst
+is returned.
+.Fa dst should be long enough to also contain the trailing
+string terminator. If
+.Fa srclen
+is not a multiple of 4, or
+.Fa dst
+is not long enough to contain the encoded data, this function returns
+-1 and sets
+.Va keynote_errno
+to
+.Er ERROR_SYNTAX .
+.Pp
+.Fn kn_decode_base64
+decodes the Base64-encoded data stored in
+.Fa src
+and stores the result in
+.Fa dst ,
+which is of length
+.Fa dstlen .
+The actual length of the decoded data is returned on success. On
+failure, this function returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_SYNTAX ,
+denoting either an invalid Base64 encoding or insufficient space in
+.Fa dst .
+.Pp
+.Fn kn_encode_hex
+encodes in ASCII-hexadecimal format the data of length
+.Fa srclen
+contained in
+.Fa src .
+This function allocates a chunk of memory to store the result, which
+is returned in
+.Fa dst .
+Thus, this function should be used as follows:
+.Bd -literal
+ char *dst;
+
+ kn_encode_hex(src, &dst, srclen);
+.Ed
+.Pp
+The length of the allocated buffer will be (2 * srclen + 1). On
+success, this function returns 0. On failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_MEMORY
+if it failed to allocate enough memory,
+.Er ERROR_SYNTAX
+if
+.Fa dst
+was
+.Dv NULL .
+.Pp
+.Fn kn_decode_hex
+decodes the ASCII hex-encoded string in
+.Fa src
+and stores the result in a memory chunk allocated by the function. A
+pointer to that memory is stored in
+.Fa dst .
+The length of the allocated memory will be (strlen(src) / 2). On
+success, this function returns 0. On failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_MEMORY
+if it could not allocate enough memory, or
+.Er ERROR_SYNTAX
+if
+.Fa dst
+was
+.Dv NULL ,
+or the length of
+.Fa src
+is not even.
+.Pp
+.Fn kn_encode_key
+ASCII-encodes a cryptographic key. The binary representation of the
+key is contained in
+.Fa dc .
+The field
+.Fa dec_key
+in that structure is a pointer to some cryptographic algorithm
+dependent information describing the key. In this implementation, this
+pointer should be a
+.Fa DSA *
+or
+.Fa RSA *
+for DSA or RSA keys respectively, as used in the SSL library, or a
+.Fa keynote_binary *
+for cryptographic keys whose algorithm
+.Nm KeyNote
+does not know about but the application wishes to include in the
+action authorizers (and thus need to be canonicalized). The field
+.Fa dec_algorithm
+describes the cryptographic algorithm, and may be one of
+.Dv KEYNOTE_ALGORITHM_DSA ,
+.Dv KEYNOTE_ALGORITHM_RSA ,
+or
+.Dv KEYNOTE_ALGORITHM_BINARY
+in this implementation.
+.Pp
+.Fa iencoding
+describes how the key should be binary-encoded. This implementation
+supports
+.DV INTERNAL_ENC_PKCS1
+for RSA keys,
+.Dv INTERNAL_ENC_ASN1
+for DSA keys, and
+.Dv INTERNAL_ENC_NONE
+for BINARY keys.
+.Fa encoding
+describes what ASCII encoding should be applied to the key. Valid
+values are
+.Dv ENCODING_HEX
+and
+.Dv ENCODING_BASE64 ,
+for hexadecimal and Base64 encoding respectively.
+.Fa keytype
+is one of
+.Dv KEYNOTE_PUBLIC_KEY
+or
+.Dv KEYNOTE_PRIVATE_KEY
+to indicate whether the key is public or private. Private keys have
+the string
+.Dv KEYNOTE_PRIVATE_KEY_PREFIX
+(defined in keynote.h) prefixed to the algorithm name. On success,
+this function returns a string containing the encoded key. On failure,
+it returns
+.Dv NULL
+and sets
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND
+if the
+.Fa dc
+argument was invalid,
+.Er ERROR_MEMORY
+if it failed to allocate the necessary memory, or
+.Er ERROR_SYNTAX
+if the key to be converted was invalid.
+.Pp
+.Fn kn_decode_key
+decodes the ASCII-encoded string contained in
+.Fa key .
+The result is placed in
+.Fa dc ,
+with
+.Fa dec_algorithm
+describing the algorithm (see
+.Xr kn_encode_key 3 ),
+and
+.Fa dec_key
+pointing to an algorithm-dependent structure. In this implementation,
+this is an SSLeay/OpenSSL-defined
+.Fa DSA *
+for DSA keys,
+.Fa RSA *
+for RSA keys, and a
+.Fa keynote_binary *
+for BINARY keys.
+.Fa keytype
+takes the values
+.Dv KEYNOTE_PUBLIC_KEY
+or
+.Dv KEYNOTE_PRIVATE_KEY
+to specify a public or private key, where applicable. On success, this
+function returns 0. On failure, it returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_MEMORY
+if necessary memory could not be allocated, or
+.Er ERROR_SYNTAX
+if the key or the ASCII encoding was malformed.
+.Pp
+.Fn kn_sign_assertion
+produces the cryptographic signature for the assertion of length
+.Fa len
+stored in
+.Fa assertion ,
+using the ASCII-encoded cryptographic key contained in
+.Fa key .
+The type of signature to be produced is described by the string
+.Fa algorithm .
+Possible values for this string are
+.Dv SIG_RSA_SHA1_HEX
+.Dv SIG_RSA_SHA1_BASE64 ,
+.Dv SIG_RSA_MD5_HEX ,
+and
+.Dv SIG_RSA_MD5_HEX
+for RSA keys,
+.Dv SIG_DSA_SHA1_HEX
+and
+.Dv SIG_DSA_SHA1_BASE64
+for DSA keys. No other cryptographic signatures are currently
+supported by this implementation. If
+.Fa vflag
+is set to 1, then the generated signature will also be verified. On
+success, this function returns a string containing the ASCII-encoded
+signature, without modifying the
+.Fa assertion .
+On failure, it returns
+.Dv NULL
+and sets
+.Va keynote_errno
+to
+.Er ERROR_NOTFOUND
+if one of the arguments was
+.Dv NULL,
+.Er ERROR_MEMORY
+if necessary memory could not be allocated, or
+.Er ERROR_SYNTAX
+if the
+.Fa algorithm ,
+the
+.Fa key ,
+or the
+.Fa assertion
+(if signature verification was requested) was invalid.
+.Pp
+.Fn kn_verify_assertion
+verifies the cryptographic signature on the assertion of length
+.Fa len
+contained in string
+.Fa assertion .
+On success, this function returns
+.Dv SIGRESULT_TRUE
+if the signature could be verified, or
+.Dv SIGRESULT_FALSE
+otherwise. On failure, this function returns -1 and sets
+.Va keynote_errno
+to
+.Er ERROR_MEMORY
+if necessary memory could not be allocated, or
+.Er ERROR_SYNTAX
+if the assertion contained a syntactic error, or the cryptographic
+algorithm was not supported.
+.Pp
+.Sh FILES
+.Fd keynote.h
+.Fd libkeynote.a
+.Sh SEE ALSO
+.Xr keynote-keygen 1 ,
+.Xr keynote-sign 1 ,
+.Xr keynote-sigver 1 ,
+.Xr keynote-verify 1
+.Bl -tag -width "AAAAAAA"
+.It ``The KeyNote Trust-Management System''
+M. Blaze, J. Feigenbaum, A. D. Keromytis,
+Internet Drafts, draft-ietf-trustmgt-keynote-00.txt
+.It ``Decentralized Trust Management''
+M. Blaze, J. Feigenbaum, J. Lacy,
+1996 IEEE Conference on Privacy and Security
+.It ``Compliance-Checking in the PolicyMaker Trust Management System''
+M. Blaze, J. Feigenbaum, M. Strauss,
+1998 Financial Crypto Conference
+.El
+.Sh AUTHOR
+Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.Sh WEB PAGE
+http://www.cis.upenn.edu/~keynote
+.Sh DIAGNOSTICS
+The return values of all the functions have been given along with the
+function description above.
+.Sh BUGS
+None that we know of.
+If you find any, please report them at
+.Bd -literal -offset indent -compact
+keynote@research.att.com
+.Ed
diff --git a/lib/libkeynote/man/keynote.4 b/lib/libkeynote/man/keynote.4
new file mode 100644
index 00000000000..892585dc3af
--- /dev/null
+++ b/lib/libkeynote/man/keynote.4
@@ -0,0 +1,266 @@
+.\" $OpenBSD: keynote.4,v 1.1 1999/05/23 22:11:08 angelos Exp $
+.\"
+.\" The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.\"
+.\" This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+.\" in April-May 1998
+.\"
+.\" Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+.\"
+.\" Permission to use, copy, and modify this software without fee
+.\" is hereby granted, provided that this entire notice is included in
+.\" all copies of any software which is or includes a copy or
+.\" modification of this software.
+.\" You may use this code under the GNU public license if you so wish. Please
+.\" contribute changes back to the author.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+.\" REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+.\" MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+.\" PURPOSE.
+.\"
+.Dd May 22, 1999
+.Dt KeyNote 3
+.Os
+.\" .TH KeyNote 4 local
+.Sh NAME
+.Nm KeyNote
+.Nd A Trust-Management System
+.Sh SYNOPSIS
+.Fd #include <keynote.h>
+.Fd Link options: -lkeynote -lm -lcrypto
+.Sh DESCRIPTION
+For more details on
+.Nm KeyNote ,
+see the web page
+.Bd -literal -offset indent
+ http://www.cis.upenn.edu/~keynote
+.Ed
+.Pp
+Additional details on the API and the various tools are given in the
+man pages listed at the end of this manual.
+.Pp
+Trust management, introduced in the PolicyMaker system, is a unified
+approach to specifying and interpreting security policies,
+credentials, and relationships; it allows direct authorization of
+security-critical actions. A trust-management system provides
+standard, general-purpose mechanisms for specifying application
+security policies and credentials. Trust-management credentials
+describe a specific delegation of trust and subsume the role of public
+key certificates; unlike traditional certificates, which bind keys to
+names, credentials can bind keys directly to the authorization to
+perform specific tasks.
+
+A trust-management system has five basic components:
+
+.nf
+* A language for describing `actions,' which are operations with
+ security consequences that are to be controlled by the system.
+
+* A mechanism for identifying `principals,' which are entities that
+ can be authorized to perform actions.
+
+* A language for specifying application `policies,' which govern the
+ actions that principals are authorized to perform.
+
+* A language for specifying `credentials,' which allow principals
+ to delegate authorization to other principals.
+
+* A `compliance checker,' which provides a service to applications
+ for determining how an action requested by principals should be
+ handled, given a policy and a set of credentials.
+.fi
+
+The trust-management approach has a number of advantages over other
+mechanisms for specifying and controlling authorization, especially
+when security policy is distributed over a network or is otherwise
+decentralized.
+
+Trust management unifies the notions of security policy, credentials,
+access control, and authorization. An application that uses a
+trust-management system can simply ask the compliance checker whether
+a requested action should be allowed. Furthermore, policies and
+credentials are written in standard languages that are shared by all
+trust-managed applications; the security configuration mechanism for
+one application carries exactly the same syntactic and semantic
+structure as that of another, even when the semantics of the
+applications themselves are quite different.
+
+Trust-management policies are easy to distribute across networks,
+helping to avoid the need for application-specific distributed policy
+configuration mechanisms, access control lists, and certificate
+parsers and interpreters.
+
+For a general discussion of the use of trust management in distributed
+system security, see the papers listed at the end of this manual.
+
+KeyNote is a simple and flexible trust-management system designed to
+work well for a variety of large- and small- scale Internet-based
+applications. It provides a single, unified language for both local
+policies and credentials. KeyNote policies and credentials, called
+`assertions,' contain predicates that describe the trusted actions
+permitted by the holders of specific public keys. KeyNote assertions
+are essentially small, highly-structured programs. A signed assertion,
+which can be sent over an untrusted network, is also called a
+`credential assertion.' Credential assertions, which also serve the
+role of certificates, have the same syntax as policy assertions but
+are also signed by the principal delegating the trust.
+
+In KeyNote:
+
+.nf
+* Actions are specified as a collection of name-value pairs.
+
+* Principal names can be any convenient string and can directly
+ represent cryptographic public keys.
+
+* The same language is used for both policies and credentials.
+
+* The policy and credential language is concise, highly expressive,
+ human readable and writable, and compatible with a variety of
+ storage and transmission media, including electronic mail.
+
+* The compliance checker returns an application-configured `policy
+ compliance value' that describes how a request should be handled
+ by the application. Policy compliance values are always
+ positively derived from policy and credentials, facilitating
+ analysis of KeyNote-based systems.
+
+* Compliance checking is efficient enough for high-performance and
+ real-time applications.
+.fi
+
+In KeyNote, the authority to perform trusted actions is associated
+with one or more `principals.' A principal may be a physical entity, a
+process in an operating system, a public key, or any other convenient
+abstraction. KeyNote principals are identified by a string called a
+`Principal Identifier.' In some cases, a Principal Identifier will
+contain a cryptographic key interpreted by the KeyNote system (e.g.,
+for credential signature verification). In other cases, Principal
+Identifiers may have a structure that is opaque to KeyNote.
+
+Principals perform two functions of concern to KeyNote: They request
+`actions' and they issue `assertions.' Actions are any trusted
+operations that an application places under KeyNote control.
+Assertions delegate the authorization to perform actions to other
+principals.
+
+Actions are described to the KeyNote compliance checker in terms of a
+collection of name-value pairs called an `action attribute set.' The
+action attribute set is created by the invoking application. Its
+structure and format are described in detail in Section 3 of this
+document.
+
+KeyNote provides advice to applications on the interpretation of
+policy with regard to specific requested actions. Applications invoke
+the KeyNote compliance checker by issuing a `query' containing a
+proposed action attribute set and identifying the principal(s)
+requesting it. The KeyNote system determines and returns an
+appropriate `policy compliance value' from an ordered set of possible
+responses.
+
+The policy compliance value returned from a KeyNote query advises the
+application how to process the requested action. In the simplest case,
+the compliance value is Boolean (e.g., "reject" or "approve").
+Assertions can also be written to select from a range of possible
+compliance values, when appropriate for the application (e.g., "no
+access", "restricted access", "full access"). Applications can
+configure the relative ordering (from `weakest' to `strongest') of
+compliance values at query time.
+
+Assertions are the basic programming unit for specifying policy and
+delegating authority. Assertions describe the conditions under which a
+principal authorizes actions requested by other principals. An
+assertion identifies the principal that made it, which other
+principals are being authorized, and the conditions under which the
+authorization applies. The syntax of assertions is given in Section 4.
+
+A special principal, whose identifier is "POLICY", provides the root
+of trust in KeyNote. "POLICY" is therefore considered to be authorized
+to perform any action.
+
+Assertions issued by the "POLICY" principal are called `policy
+assertions' and are used to delegate authority to otherwise untrusted
+principals. The KeyNote security policy of an application consists of
+a collection of policy assertions.
+
+When a principal is identified by a public key, it can digitally sign
+assertions and distribute them over untrusted networks for use by
+other KeyNote compliance checkers. These signed assertions are also
+called `credentials,' and serve a role similar to that of traditional
+public key certificates. Policies and credentials share the same
+syntax and are evaluated according to the same semantics. A principal
+can therefore convert its policy assertions into credentials simply by
+digitally signing them.
+
+KeyNote is designed to encourage the creation of human-readable
+policies and credentials that are amenable to transmission and storage
+over a variety of media. Its assertion syntax is inspired by the
+format of RFC822-style message headers. A KeyNote assertion contains a
+sequence of sections, called `fields,' each of which specifying one
+aspect of the assertion's semantics. Fields start with an identifier
+at the beginning of a line and continue until the next field is
+encountered. For example:
+
+.nf
+ KeyNote-Version: 2
+ Comment: A simple, if contrived, email certificate for user mab
+ Local-Constants: ATT_CA_key = "RSA:acdfa1df1011bbac"
+ mab_key = "DSA:deadbeefcafe001a"
+ Authorizer: ATT_CA_key
+ Licensees: mab_key
+ Conditions: ((app_domain == "email") # valid for email only
+ && (address == "mab@research.att.com"));
+ Signature: "RSA-SHA1:f00f2244"
+.fi
+
+For the exact meanings of all the fields, see the RFC reference at the
+end of this manual.
+
+KeyNote semantics resolve the relationship between an application's
+policy and actions requested by other principals, as supported by
+credentials. The KeyNote compliance checker processes the assertions
+against the action attribute set to determine the policy compliance
+value of a requested action. These semantics are defined in Section 5.
+
+An important principle in KeyNote's design is `assertion
+monotonicity'; the policy compliance value of an action is always
+positively derived from assertions made by trusted principals.
+Removing an assertion never results in increasing the compliance value
+returned by KeyNote for a given query. The monotonicity property can
+simplify the design and analysis of complex network-based security
+protocols; network failures that prevent the transmission of
+credentials can never result in spurious authorization of dangerous
+actions.
+.Pp
+.Sh FILES
+.Fd keynote.h
+.Fd libkeynote.a
+.Sh SEE ALSO
+.Xr keynote 3 ,
+.Xr keynote-keygen 1 ,
+.Xr keynote-sign 1 ,
+.Xr keynote-sigver 1 ,
+.Xr keynote-verify 1
+.Bl -tag -width "AAAAAAA"
+.It ``The KeyNote Trust-Management System''
+M. Blaze, J. Feigenbaum, A. D. Keromytis,
+Internet Drafts, draft-ietf-trustmgt-keynote-00.txt
+.It ``Decentralized Trust Management''
+M. Blaze, J. Feigenbaum, J. Lacy,
+1996 IEEE Conference on Privacy and Security
+.It ``Compliance-Checking in the PolicyMaker Trust Management System''
+M. Blaze, J. Feigenbaum, M. Strauss,
+1998 Financial Crypto Conference
+.El
+.Sh AUTHOR
+Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+.Sh WEB PAGE
+http://www.cis.upenn.edu/~keynote
+.Sh BUGS
+None that we know of.
+If you find any, please report them at
+.Bd -literal -offset indent -compact
+keynote@research.att.com
+.Ed
diff --git a/lib/libkeynote/parse_assertion.c b/lib/libkeynote/parse_assertion.c
new file mode 100644
index 00000000000..4427782d54e
--- /dev/null
+++ b/lib/libkeynote/parse_assertion.c
@@ -0,0 +1,623 @@
+/* $OpenBSD: parse_assertion.c,v 1.1 1999/05/23 22:11:06 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include "assertion.h"
+#include "environment.h"
+#include "signature.h"
+
+/* Globals */
+struct assertion *keynote_current_assertion = (struct assertion *) NULL;
+int keynote_errno = 0;
+
+extern int keynote_in_action_authorizers(void *, int);
+
+/*
+ * Recurse on graph discovery.
+ */
+static int
+rec_evaluate_query(struct assertion *as)
+{
+ struct assertion *ast;
+ struct keylist *kl;
+ int i, s;
+
+ as->as_kresult = KRESULT_IN_PROGRESS;
+
+ /*
+ * If we get the minimum result or an error from evaluating this
+ * assertion, we don't need to recurse.
+ */
+ keynote_evaluate_assertion(as);
+ if (keynote_errno != 0)
+ {
+ as->as_kresult = KRESULT_DONE;
+ if (keynote_errno)
+ as->as_error = keynote_errno;
+ if (keynote_errno == ERROR_MEMORY)
+ return -1;
+ else
+ {
+ keynote_errno = 0; /* Ignore syntax errors for now */
+ return 0;
+ }
+ }
+
+ if (as->as_result == 0)
+ {
+ as->as_kresult = KRESULT_DONE;
+ return as->as_result;
+ }
+
+ for (kl = as->as_keylist;
+ kl != (struct keylist *) NULL;
+ kl = kl->key_next)
+ {
+ switch (keynote_in_action_authorizers(kl->key_key, kl->key_alg))
+ {
+ case -1:
+ as->as_kresult = KRESULT_DONE;
+ if (keynote_errno == ERROR_MEMORY)
+ {
+ as->as_error = ERROR_MEMORY;
+ return -1;
+ }
+ else
+ {
+ keynote_errno = 0; /* Reset */
+ continue;
+ }
+
+ case RESULT_FALSE: /* Not there, check for assertions instead */
+ break;
+
+ case RESULT_TRUE: /* Ok, don't bother with assertions */
+ keynote_current_assertion = (struct assertion *) NULL;
+ continue;
+ }
+
+ for (i = 0;; i++)
+ {
+ ast = keynote_find_assertion(kl->key_key, i, kl->key_alg);
+ if (ast == (struct assertion *) NULL)
+ break;
+
+ if (ast->as_kresult == KRESULT_IN_PROGRESS) /* Cycle detected */
+ continue;
+
+ if (ast->as_kresult == KRESULT_UNTOUCHED) /* Recurse if needed */
+ rec_evaluate_query(ast);
+
+ /* Check for errors */
+ if (keynote_errno == ERROR_MEMORY)
+ {
+ as->as_error = ERROR_MEMORY;
+ as->as_kresult = KRESULT_DONE;
+ return -1;
+ }
+ else
+ keynote_errno = 0; /* Reset */
+ }
+ }
+
+ keynote_current_assertion = as;
+ s = keynote_parse_keypred(as, 0);
+ keynote_current_assertion = (struct assertion *) NULL;
+
+ if (keynote_errno == ERROR_MEMORY)
+ {
+ as->as_error = ERROR_MEMORY;
+ as->as_kresult = KRESULT_DONE;
+ return -1;
+ }
+ else
+ if (keynote_errno)
+ {
+ keynote_errno = 0;
+ s = 0;
+ }
+
+ /* Keep lower of two */
+ as->as_result = (as->as_result < s ? as->as_result : s);
+
+ /* Check the signature now if we haven't done so already */
+ if (as->as_sigresult == SIGRESULT_UNTOUCHED)
+ {
+ if (!(as->as_flags & ASSERT_FLAG_LOCAL))
+ as->as_sigresult = keynote_sigverify_assertion(as);
+ else
+ as->as_sigresult = SIGRESULT_TRUE; /* Trusted assertion */
+ }
+
+ if (as->as_sigresult != SIGRESULT_TRUE)
+ {
+ as->as_result = 0;
+ as->as_sigresult = SIGRESULT_FALSE;
+ if (keynote_errno != ERROR_MEMORY)
+ keynote_errno = 0; /* Reset */
+ else
+ {
+ as->as_error = ERROR_MEMORY;
+ as->as_kresult = KRESULT_DONE;
+ return -1;
+ }
+ }
+
+ as->as_kresult = KRESULT_DONE;
+ return as->as_result;
+}
+
+/*
+ * Fix the Authorizer/Licencees/Signature fields. If the first argument is
+ * empty, fix all assertions. The second argument specifies whether the
+ * Signature field should be parsed or not.
+ */
+static int
+keynote_fix_fields(struct assertion *ast, int sigfield)
+{
+ struct assertion *as;
+ int i;
+
+ /* Signature generation/verification handling, no need to eval Licensees */
+ if (ast != (struct assertion *) NULL)
+ {
+ /* Authorizer */
+ if (keynote_evaluate_authorizer(ast, 1) != RESULT_TRUE)
+ return -1;
+
+ /* Signature */
+ if ((sigfield) && (ast->as_signature_string_s != (char *) NULL))
+ if (keynote_evaluate_authorizer(ast, 0) != RESULT_TRUE)
+ return -1;
+
+ return RESULT_TRUE;
+ }
+
+ for (i = 0; i < HASHTABLESIZE; i++)
+ for (as = keynote_current_session->ks_assertion_table[i];
+ as != (struct assertion *) NULL;
+ as = as->as_next)
+ {
+ if (!(as->as_internalflags & ASSERT_IFLAG_NEEDPROC) &&
+ !(as->as_internalflags & ASSERT_IFLAG_WEIRDLICS) &&
+ !(as->as_internalflags & ASSERT_IFLAG_WEIRDAUTH) &&
+ !(as->as_internalflags & ASSERT_IFLAG_WEIRDSIG))
+ continue;
+
+ /* Parse the Signature field */
+ if (((as->as_internalflags & ASSERT_IFLAG_WEIRDSIG) ||
+ (as->as_internalflags & ASSERT_IFLAG_NEEDPROC)) &&
+ (as->as_signature_string_s != (char *) NULL))
+ if (keynote_evaluate_authorizer(as, 0) == -1)
+ {
+ if (keynote_errno)
+ as->as_error = keynote_errno;
+ if (keynote_errno == ERROR_MEMORY)
+ return -1;
+ else
+ keynote_errno = 0;
+ }
+
+ /* Parse the Licensees field */
+ if ((as->as_internalflags & ASSERT_IFLAG_WEIRDLICS) ||
+ (as->as_internalflags & ASSERT_IFLAG_NEEDPROC))
+ if (keynote_parse_keypred(as, 1) == -1)
+ {
+ if (keynote_errno)
+ as->as_error = keynote_errno;
+ if (keynote_errno == ERROR_MEMORY)
+ return -1;
+ else
+ keynote_errno = 0;
+ }
+
+ /* Parse the Authorizer field */
+ if ((as->as_internalflags & ASSERT_IFLAG_WEIRDAUTH) ||
+ (as->as_internalflags & ASSERT_IFLAG_NEEDPROC))
+ if (keynote_evaluate_authorizer(as, 1) == -1)
+ {
+ if (keynote_errno)
+ as->as_error = keynote_errno;
+ if (keynote_errno == ERROR_MEMORY)
+ return -1;
+ else
+ keynote_errno = 0;
+ }
+ }
+
+ /* Reposition if necessary */
+ for (i = 0; i < HASHTABLESIZE; i++)
+ for (as = keynote_current_session->ks_assertion_table[i];
+ as != (struct assertion *) NULL;
+ as = as->as_next)
+ if (((as->as_internalflags & ASSERT_IFLAG_WEIRDAUTH) &&
+ !(as->as_internalflags & ASSERT_IFLAG_PROCESSED)) ||
+ (as->as_internalflags & ASSERT_IFLAG_NEEDPROC))
+ {
+ as->as_internalflags &= ~ASSERT_IFLAG_NEEDPROC;
+ as->as_internalflags |= ASSERT_IFLAG_PROCESSED;
+ keynote_sremove_assertion(keynote_current_session->ks_id,
+ as->as_id);
+
+ if (keynote_add_htable(as, 1) != RESULT_TRUE)
+ return -1;
+
+ /* Point to begining of the previous list. */
+ i--;
+ break;
+ }
+
+ return RESULT_TRUE;
+}
+
+/*
+ * Find the trust graph. This is a depth-first search, starting at
+ * POLICY assertions.
+ */
+int
+keynote_evaluate_query(void)
+{
+ struct assertion *as;
+ int p, prev;
+ int i;
+
+ /* Fix the authorizer/licensees/signature fields */
+ if (keynote_fix_fields((struct assertion *) NULL, 0) != RESULT_TRUE)
+ return -1;
+
+ /* Find POLICY assertions and try to evaluate the query. */
+ for (i = 0, prev = 0; i < HASHTABLESIZE; i++)
+ for (as = keynote_current_session->ks_assertion_table[i];
+ as != (struct assertion *) NULL;
+ as = as->as_next)
+ if ((as->as_authorizer != (void *) NULL) && /* Paranoid */
+ (as->as_signeralgorithm == KEYNOTE_ALGORITHM_NONE))
+ if ((!strcmp("POLICY", as->as_authorizer)) &&
+ (as->as_flags & ASSERT_FLAG_LOCAL))
+ {
+ if ((p = rec_evaluate_query(as)) == -1)
+ {
+ if (keynote_errno)
+ as->as_error = keynote_errno;
+ if (keynote_errno == ERROR_MEMORY)
+ return -1;
+ else
+ {
+ keynote_errno = 0;
+ continue;
+ }
+ }
+
+ if (p > prev)
+ prev = p;
+
+ /* If we get the highest possible return value, just return */
+ if (prev == (keynote_current_session->ks_values_num - 1))
+ return prev;
+ }
+
+ return prev;
+}
+
+/*
+ * Return keyword type.
+ */
+static int
+whichkeyword(char *start, char *end)
+{
+ int len = (end - start);
+
+ if (len <= 0)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if (!strncasecmp("keynote-version:", start, len))
+ return KEYWORD_VERSION;
+
+ if (!strncasecmp("local-constants:", start, len))
+ return KEYWORD_LOCALINIT;
+
+ if (!strncasecmp("authorizer:", start, len))
+ return KEYWORD_AUTHORIZER;
+
+ if (!strncasecmp("licensees:", start, len))
+ return KEYWORD_LICENSEES;
+
+ if (!strncasecmp("conditions:", start, len))
+ return KEYWORD_CONDITIONS;
+
+ if (!strncasecmp("signature:", start, len))
+ return KEYWORD_SIGNATURE;
+
+ if (!strncasecmp("comment:", start, len))
+ return KEYWORD_COMMENT;
+
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+}
+
+/*
+ * Parse an assertion. Set keynote_errno to ERROR_SYNTAX if parsing
+ * failed due to certificate badness, and ERROR_MEMORY if memory
+ * problem. If more than one assertions have been passed in the
+ * buffer, they will be linked.
+ */
+struct assertion *
+keynote_parse_assertion(char *buf, int len, int assertion_flags)
+{
+ int i, j, seen_field = 0, ver = 0, end_of_assertion = 0;
+ char *ks, *ke, *ts, *te = (char *) NULL;
+ struct assertion *as;
+
+ /* Allocate memory for assertion */
+ as = (struct assertion *) calloc(1, sizeof(struct assertion));
+ if (as == (struct assertion *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (struct assertion *) NULL;
+ }
+
+ /* Keep a copy of the assertion around */
+ as->as_buf = strdup(buf);
+ if (as->as_buf == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ keynote_free_assertion(as);
+ return (struct assertion *) NULL;
+ }
+
+ as->as_flags = assertion_flags & ~(ASSERT_FLAG_SIGGEN |
+ ASSERT_FLAG_SIGVER);
+
+ /* Skip any leading whitespace */
+ for (i = 0, j = len; i < j && isspace(as->as_buf[i]); i++)
+ ;
+
+ /* Keyword must start at begining of buffer or line */
+ if ((i >= j) || ((i != 0) && (as->as_buf[i - 1] != '\n')))
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ while (i < j) /* Decomposition loop */
+ {
+ ks = as->as_buf + i;
+
+ /* Mark begining of assertion for signature purposes */
+ if (as->as_startofsignature == (char *) NULL)
+ as->as_startofsignature = ks;
+
+ if (as->as_buf[i] == '#') /* Comment */
+ {
+ seen_field = 1;
+
+ /* Skip until the end of line */
+ while ((i< j) && as->as_buf[++i] != '\n')
+ ;
+
+ continue; /* Loop */
+ }
+
+ /* Advance until we find a keyword separator */
+ for (; (as->as_buf[i] != ':') && (i < j); i++)
+ ;
+
+ if (i + 1 > j)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ /* ks points at begining of keyword, ke points at end */
+ ke = as->as_buf + i;
+
+ /* ts points at begining of value field */
+ ts = as->as_buf + i + 1; /* Skip ':' */
+
+ /*
+ * Find the end of the field -- means end of buffer,
+ * a newline followed by a non-whitespace character,
+ * or two newlines.
+ */
+ while (++i <= j)
+ {
+ /* If end of buffer, we're at the end of the field */
+ if (i == j)
+ {
+ end_of_assertion = 1;
+ te = as->as_buf + i;
+ break;
+ }
+
+ /* If two newlines, end of assertion */
+ if ((as->as_buf[i] == '\n') && (i + 1 < j) &&
+ (as->as_buf[i + 1] == '\n'))
+ {
+ end_of_assertion = 1;
+ te = as->as_buf + i;
+ break;
+ }
+
+ /* If newline followed by non-whitespace or comment character */
+ if ((as->as_buf[i] == '\n') &&
+ (!isspace(as->as_buf[i + 1])) && (as->as_buf[i + 1] != '#'))
+ {
+ te = as->as_buf + i;
+ break;
+ }
+ }
+
+ i++;
+
+ /*
+ * On each of the cases (except the first), we check that:
+ * - we've already seen a keynote-version field (and that
+ * it's the first one that appears in the assertion)
+ * - the signature field, if present, is the last one
+ * - no field appears more than once
+ */
+ switch (whichkeyword(ks, ke))
+ {
+ case -1:
+ keynote_free_assertion(as);
+ return (struct assertion *) NULL;
+
+ case KEYWORD_VERSION:
+ if ((ver == 1) || (seen_field == 1))
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ /* Test for version correctness */
+ keynote_get_envlist(ts, te, 1);
+ if (keynote_errno != 0)
+ {
+ keynote_free_assertion(as);
+ return (struct assertion *) NULL;
+ }
+
+ ver = 1;
+ break;
+
+ case KEYWORD_LOCALINIT:
+ if (as->as_env != (struct environment *) NULL)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ as->as_env = keynote_get_envlist(ts, te, 0);
+ if (keynote_errno != 0)
+ {
+ keynote_free_assertion(as);
+ return (struct assertion *) NULL;
+ }
+ break;
+
+ case KEYWORD_AUTHORIZER:
+ if (as->as_authorizer_string_s != (void *) NULL)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ as->as_authorizer_string_s = ts;
+ as->as_authorizer_string_e = te;
+ break;
+
+ case KEYWORD_LICENSEES:
+ if (as->as_keypred_s != (char *) NULL)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ as->as_keypred_s = ts;
+ as->as_keypred_e = te;
+ break;
+
+ case KEYWORD_CONDITIONS:
+ if (as->as_conditions_s != (char *) NULL)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ as->as_conditions_s = ts;
+ as->as_conditions_e = te;
+ break;
+
+ case KEYWORD_SIGNATURE:
+ if (as->as_signature_string_s != (char *) NULL)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ end_of_assertion = 1;
+ as->as_allbutsignature = ks;
+ as->as_signature_string_s = ts;
+ as->as_signature_string_e = te;
+ break;
+
+ case KEYWORD_COMMENT:
+ if (as->as_comment_s != (char *) NULL)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ as->as_comment_s = ts;
+ as->as_comment_e = te;
+ break;
+ }
+
+ seen_field = 1;
+ if (end_of_assertion == 1)
+ break;
+ }
+
+ /* Check that the basic fields are there */
+ if (as->as_authorizer_string_s == (char *) NULL)
+ {
+ keynote_free_assertion(as);
+ keynote_errno = ERROR_SYNTAX;
+ return (struct assertion *) NULL;
+ }
+
+ /* Signature generation/verification handling */
+ if (assertion_flags & ASSERT_FLAG_SIGGEN)
+ {
+ if (keynote_fix_fields(as, 0) != RESULT_TRUE)
+ {
+ keynote_free_assertion(as);
+ return (struct assertion *) NULL;
+ }
+ }
+ else
+ if (assertion_flags & ASSERT_FLAG_SIGVER)
+ if (keynote_fix_fields(as, 1) != RESULT_TRUE)
+ {
+ keynote_free_assertion(as);
+ return (struct assertion *) NULL;
+ }
+
+ return as;
+}
diff --git a/lib/libkeynote/signature.c b/lib/libkeynote/signature.c
new file mode 100644
index 00000000000..3533d8ee41f
--- /dev/null
+++ b/lib/libkeynote/signature.c
@@ -0,0 +1,1420 @@
+/* $OpenBSD: signature.c,v 1.1 1999/05/23 22:11:06 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+/*
+ * Support for X509 keys and signing added by Ben Laurie <ben@algroup.co.uk>
+ * 3 May 1999
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include "signature.h"
+
+static const char hextab[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+/*
+ * Actual conversion to hex.
+ */
+static void
+bin2hex(unsigned char *data, unsigned char *buffer, int len)
+{
+ int off = 0;
+
+ while(len > 0)
+ {
+ buffer[off++] = hextab[*data >> 4];
+ buffer[off++] = hextab[*data & 0xF];
+ data++;
+ len--;
+ }
+}
+
+/*
+ * Encode a binary string with hex encoding. Return 0 on success.
+ */
+int
+kn_encode_hex(unsigned char *buf, char **dest, int len)
+{
+ keynote_errno = 0;
+ if (dest == (char **) NULL)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ *dest = (char *) calloc(2 * len + 1, sizeof(char));
+ if (*dest == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ bin2hex(buf, *dest, len);
+ return 0;
+}
+
+/*
+ * Decode a hex encoding. Return 0 on success. The second argument
+ * will be half as large as the first.
+ */
+int
+kn_decode_hex(char *hex, char **dest)
+{
+ int i, decodedlen;
+ char ptr[3];
+
+ keynote_errno = 0;
+ if (dest == (char **) NULL)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ if (strlen(hex) % 2) /* Should be even */
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ decodedlen = strlen(hex) / 2;
+ *dest = (char *) calloc(decodedlen, sizeof(char));
+ if (*dest == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ ptr[2] = '\0';
+ for (i = 0; i < decodedlen; i++)
+ {
+ ptr[0] = hex[2 * i];
+ ptr[1] = hex[(2 * i) + 1];
+ (*dest)[i] = (unsigned char) strtoul(ptr, (char **) NULL, 16);
+ }
+
+ return 0;
+}
+
+void
+keynote_free_key(void *key, int type)
+{
+ if (key == (void *) NULL)
+ return;
+
+#ifdef CRYPTO
+ /* DSA keys */
+ if (type == KEYNOTE_ALGORITHM_DSA)
+ {
+ DSA_free(key);
+ return;
+ }
+
+ /* RSA keys */
+ if (type == KEYNOTE_ALGORITHM_RSA)
+ {
+ RSA_free(key);
+ return;
+ }
+
+ /* X509 keys */
+ if (type == KEYNOTE_ALGORITHM_X509)
+ {
+ RSA_free(key); /* RSA-specific */
+ return;
+ }
+#endif /* CRYPTO */
+
+#ifdef PGPLIB
+ /* PGP keys */
+ if (type == KEYNOTE_ALGORITHM_PGP)
+ {
+ /* Unsupported yet */
+ return;
+ }
+#endif /* PGPLIB */
+
+ /* BINARY keys */
+ if (type == KEYNOTE_ALGORITHM_BINARY)
+ {
+ free(((struct keynote_binary *) key)->bn_key);
+ free(key);
+ return;
+ }
+
+ /* Catch-all case */
+ if (type == KEYNOTE_ALGORITHM_NONE)
+ free(key);
+}
+
+#if defined(CRYPTO) || defined(PGPLIB)
+
+/*
+ * Map a signature to an algorithm. Return algorithm number (defined in
+ * keynote.h), or KEYNOTE_ALGORITHM_NONE if unknown.
+ * Also return in the second, third and fourth arguments the digest
+ * algorithm, ASCII and internal encodings respectively.
+ */
+static int
+keynote_get_sig_algorithm(char *sig, int *hash, int *enc, int *internal)
+{
+ if (sig == (char *) NULL)
+ return KEYNOTE_ALGORITHM_NONE;
+
+ if (!strncasecmp(SIG_DSA_SHA1_HEX, sig, SIG_DSA_SHA1_HEX_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_HEX;
+ *internal = INTERNAL_ENC_ASN1;
+ return KEYNOTE_ALGORITHM_DSA;
+ }
+
+ if (!strncasecmp(SIG_DSA_SHA1_BASE64, sig, SIG_DSA_SHA1_BASE64_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_BASE64;
+ *internal = INTERNAL_ENC_ASN1;
+ return KEYNOTE_ALGORITHM_DSA;
+ }
+
+ if (!strncasecmp(SIG_RSA_MD5_PKCS1_HEX, sig, SIG_RSA_MD5_PKCS1_HEX_LEN))
+ {
+ *hash = KEYNOTE_HASH_MD5;
+ *enc = ENCODING_HEX;
+ *internal = INTERNAL_ENC_PKCS1;
+ return KEYNOTE_ALGORITHM_RSA;
+ }
+
+ if (!strncasecmp(SIG_RSA_SHA1_PKCS1_HEX, sig, SIG_RSA_SHA1_PKCS1_HEX_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_HEX;
+ *internal = INTERNAL_ENC_PKCS1;
+ return KEYNOTE_ALGORITHM_RSA;
+ }
+
+ if (!strncasecmp(SIG_RSA_MD5_PKCS1_BASE64, sig,
+ SIG_RSA_MD5_PKCS1_BASE64_LEN))
+ {
+ *hash = KEYNOTE_HASH_MD5;
+ *enc = ENCODING_BASE64;
+ *internal = INTERNAL_ENC_PKCS1;
+ return KEYNOTE_ALGORITHM_RSA;
+ }
+
+ if (!strncasecmp(SIG_RSA_SHA1_PKCS1_BASE64, sig,
+ SIG_RSA_SHA1_PKCS1_BASE64_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_BASE64;
+ *internal = INTERNAL_ENC_PKCS1;
+ return KEYNOTE_ALGORITHM_RSA;
+ }
+
+ if (!strncasecmp(SIG_X509_SHA1_BASE64, sig, SIG_X509_SHA1_BASE64_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_BASE64;
+ *internal = INTERNAL_ENC_ASN1;
+ return KEYNOTE_ALGORITHM_X509;
+ }
+
+ if (!strncasecmp(SIG_X509_SHA1_HEX, sig, SIG_X509_SHA1_HEX_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_HEX;
+ *internal = INTERNAL_ENC_ASN1;
+ return KEYNOTE_ALGORITHM_X509;
+ }
+
+#if 0 /* Not supported yet */
+ if (!strncasecmp(SIG_ELGAMAL_SHA1_HEX, sig, SIG_ELGAMAL_SHA1_HEX_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_HEX;
+ *internal = INTERNAL_ENC_ASN1;
+ return KEYNOTE_ALGORITHM_ELGAMAL;
+ }
+
+ if (!strncasecmp(SIG_ELGAMAL_SHA1_BASE64, sig,
+ SIG_ELGAMAL_SHA1_BASE64_LEN))
+ {
+ *hash = KEYNOTE_HASH_SHA1;
+ *enc = ENCODING_BASE64;
+ *internal = INTERNAL_ENC_ASN1;
+ return KEYNOTE_ALGORITHM_ELGAMAL;
+ }
+#endif /* 0 */
+
+#ifdef PGPLIB
+ if (!strncasecmp(SIG_PGP_NATIVE, sig, SIG_PGP_NATIVE_LEN))
+ {
+ *hash = KEYNOTE_HASH_NONE;
+ *enc = ENCODING_NATIVE;
+ *internal = INTERNAL_ENC_NATIVE;
+ return KEYNOTE_ALGORITHM_PGP;
+ }
+#endif /* PGPLIB */
+
+ *hash = KEYNOTE_HASH_NONE;
+ *enc = ENCODING_NONE;
+ *internal = INTERNAL_ENC_NONE;
+ return KEYNOTE_ALGORITHM_NONE;
+}
+#endif /* CRYPTO || PGPLIB */
+
+/*
+ * Map a key to an algorithm. Return algorithm number (defined in
+ * keynote.h), or KEYNOTE_ALGORITHM_NONE if unknown.
+ * This latter is also a valid algorithm (for logical tags). Also return
+ * in the second and third arguments the ASCII and internal encodings.
+ */
+int
+keynote_get_key_algorithm(char *key, int *encoding, int *internalencoding)
+{
+#ifdef CRYPTO
+ if (!strncasecmp(DSA_HEX, key, DSA_HEX_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_ASN1;
+ *encoding = ENCODING_HEX;
+ return KEYNOTE_ALGORITHM_DSA;
+ }
+
+ if (!strncasecmp(DSA_BASE64, key, DSA_BASE64_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_ASN1;
+ *encoding = ENCODING_BASE64;
+ return KEYNOTE_ALGORITHM_DSA;
+ }
+
+ if (!strncasecmp(RSA_PKCS1_HEX, key, RSA_PKCS1_HEX_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_PKCS1;
+ *encoding = ENCODING_HEX;
+ return KEYNOTE_ALGORITHM_RSA;
+ }
+
+ if (!strncasecmp(RSA_PKCS1_BASE64, key, RSA_PKCS1_BASE64_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_PKCS1;
+ *encoding = ENCODING_BASE64;
+ return KEYNOTE_ALGORITHM_RSA;
+ }
+
+ if (!strncasecmp(X509_BASE64, key, X509_BASE64_LEN))
+ {
+ *internalencoding=INTERNAL_ENC_ASN1;
+ *encoding=ENCODING_BASE64;
+ return KEYNOTE_ALGORITHM_X509;
+ }
+
+ if (!strncasecmp(X509_HEX, key, X509_HEX_LEN))
+ {
+ *internalencoding=INTERNAL_ENC_ASN1;
+ *encoding=ENCODING_HEX;
+ return KEYNOTE_ALGORITHM_X509;
+ }
+
+#if 0 /* Not supported yet */
+ if (!strncasecmp(ELGAMAL_HEX, key, ELGAMAL_HEX_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_ASN1;
+ *encoding = ENCODING_HEX;
+ return KEYNOTE_ALGORITHM_ELGAMAL;
+ }
+
+ if (!strncasecmp(ELGAMAL_BASE64, key, ELGAMAL_BASE64_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_ASN1;
+ *encoding = ENCODING_BASE64;
+ return KEYNOTE_ALGORITHM_ELGAMAL;
+ }
+#endif /* 0 */
+#endif /* CRYPTO */
+
+#ifdef PGPLIB
+ if (!strncasecmp(PGP_NATIVE, key, PGP_NATIVE_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_NATIVE;
+ *encoding = ENCODING_NATIVE;
+ return KEYNOTE_ALGORITHM_PGP;
+ }
+#endif /* PGPLIB */
+
+ if (!strncasecmp(BINARY_HEX, key, BINARY_HEX_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_NONE;
+ *encoding = ENCODING_HEX;
+ return KEYNOTE_ALGORITHM_BINARY;
+ }
+
+ if (!strncasecmp(BINARY_BASE64, key, BINARY_BASE64_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_NONE;
+ *encoding = ENCODING_BASE64;
+ return KEYNOTE_ALGORITHM_BINARY;
+ }
+
+ *internalencoding = INTERNAL_ENC_NONE;
+ *encoding = ENCODING_NONE;
+ return KEYNOTE_ALGORITHM_NONE;
+}
+
+/*
+ * Same as keynote_get_key_algorithm(), only verify that this is
+ * a private key (just look at the prefix).
+ */
+static int
+keynote_get_private_key_algorithm(char *key, int *encoding,
+ int *internalencoding)
+{
+ if (strncasecmp(KEYNOTE_PRIVATE_KEY_PREFIX, key,
+ KEYNOTE_PRIVATE_KEY_PREFIX_LEN))
+ {
+ *internalencoding = INTERNAL_ENC_NONE;
+ *encoding = ENCODING_NONE;
+ return KEYNOTE_ALGORITHM_NONE;
+ }
+
+ return keynote_get_key_algorithm(key + KEYNOTE_PRIVATE_KEY_PREFIX_LEN,
+ encoding, internalencoding);
+}
+
+/*
+ * Decode a string to a key. Return 0 on success.
+ */
+int
+kn_decode_key(struct keynote_deckey *dc, char *key, int keytype)
+{
+#ifdef CRYPTO
+ void *kk = (void *) NULL;
+ X509 *px509Cert;
+ EVP_PKEY *pPublicKey;
+#endif /* CRYPTO */
+ unsigned char *ptr = (char *) NULL, *decoded = (char *) NULL;
+ int encoding, internalencoding, len;
+
+ keynote_errno = 0;
+ if (keytype == KEYNOTE_PRIVATE_KEY)
+ dc->dec_algorithm = keynote_get_private_key_algorithm(key, &encoding,
+ &internalencoding);
+ else
+ dc->dec_algorithm = keynote_get_key_algorithm(key, &encoding,
+ &internalencoding);
+ if (dc->dec_algorithm == KEYNOTE_ALGORITHM_NONE)
+ {
+ dc->dec_key = (void *) strdup(key);
+ if (dc->dec_key == (void *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ key = index(key, ':'); /* Move forward, to the Encoding. We're guaranteed
+ * to have a ':' character, since this is a key */
+ key++;
+
+ /* Remove ASCII encoding */
+ switch (encoding)
+ {
+ case ENCODING_NONE:
+ break;
+
+ case ENCODING_HEX:
+ len = strlen(key) / 2;
+ if (kn_decode_hex(key, (char **) &decoded) != 0)
+ return -1;
+ ptr = decoded;
+ break;
+
+ case ENCODING_BASE64:
+ len = strlen(key);
+ if (len % 4) /* Base64 encoding must be a multiple of 4 */
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ len = 3 * (len / 4);
+ decoded = (unsigned char *) calloc(len, sizeof(unsigned char));
+ ptr = decoded;
+ if (decoded == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if ((len = kn_decode_base64(key, decoded, len)) == -1)
+ return -1;
+ break;
+
+ case ENCODING_NATIVE:
+ decoded = strdup(key);
+ len = strlen(key);
+ if (decoded == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+ ptr = decoded;
+ break;
+
+ default:
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+#ifdef CRYPTO
+ /* DSA-HEX */
+ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_DSA) &&
+ (internalencoding == INTERNAL_ENC_ASN1))
+ {
+ dc->dec_key = DSA_new();
+ if (dc->dec_key == (DSA *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ kk = dc->dec_key;
+ if (keytype == KEYNOTE_PRIVATE_KEY)
+ {
+ if (d2i_DSAPrivateKey((DSA **) &kk, &decoded, len) == (DSA *) NULL)
+ {
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+ DSA_free(kk);
+ keynote_errno = ERROR_SYNTAX; /* Could be a memory error */
+ return -1;
+ }
+ }
+ else
+ {
+ if (d2i_DSAPublicKey((DSA **) &kk, &decoded, len) == (DSA *) NULL)
+ {
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+ DSA_free(kk);
+ keynote_errno = ERROR_SYNTAX; /* Could be a memory error */
+ return -1;
+ }
+ }
+
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+
+ return 0;
+ }
+
+ /* RSA-PKCS1-HEX */
+ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_RSA) &&
+ (internalencoding == INTERNAL_ENC_PKCS1))
+ {
+ dc->dec_key = RSA_new();
+ if (dc->dec_key == (RSA *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ kk = dc->dec_key;
+ if (keytype == KEYNOTE_PRIVATE_KEY)
+ {
+ if (d2i_RSAPrivateKey((RSA **) &kk, &decoded, len) == (RSA *) NULL)
+ {
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+ RSA_free(kk);
+ keynote_errno = ERROR_SYNTAX; /* Could be a memory error */
+ return -1;
+ }
+ }
+ else
+ {
+ if (d2i_RSAPublicKey((RSA **) &kk, &decoded, len) == (RSA *) NULL)
+ {
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+ RSA_free(kk);
+ keynote_errno = ERROR_SYNTAX; /* Could be a memory error */
+ return -1;
+ }
+ }
+
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+
+ return 0;
+ }
+
+ /* X509 Cert */
+ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_X509) &&
+ (internalencoding == INTERNAL_ENC_ASN1) &&
+ (keytype == KEYNOTE_PUBLIC_KEY))
+ {
+ if ((px509Cert = X509_new()) == (X509 *) NULL)
+ {
+ if (ptr)
+ free(ptr);
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ if(d2i_X509(&px509Cert, &decoded, len) == NULL)
+ {
+ if (ptr)
+ free(ptr);
+ X509_free(px509Cert);
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ if ((pPublicKey = X509_get_pubkey(px509Cert)) == (EVP_PKEY *) NULL)
+ {
+ if (ptr)
+ free(ptr);
+ X509_free(px509Cert);
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ /* RSA-specific */
+ dc->dec_key = pPublicKey->pkey.rsa;
+
+ if(ptr)
+ free(ptr);
+ return 0;
+ }
+#endif /* CRYPTO */
+
+ /* BINARY keys */
+ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_BINARY) &&
+ (internalencoding == INTERNAL_ENC_NONE))
+ {
+ dc->dec_key = (void *) calloc(1, sizeof(struct keynote_binary));
+ if (dc->dec_key == (struct keynote_binary *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ ((struct keynote_binary *) dc->dec_key)->bn_key = decoded;
+ ((struct keynote_binary *) dc->dec_key)->bn_len = len;
+ return RESULT_TRUE;
+ }
+
+ /* Add support for more algorithms here */
+
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+
+ /* This shouldn't ever be reached really */
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+}
+
+/*
+ * Compare two keys for equality. Return RESULT_TRUE if equal,
+ * RESULT_FALSE otherwise.
+ */
+int
+keynote_keycompare(void *key1, void *key2, int algorithm)
+{
+#ifdef CRYPTO
+ DSA *p1, *p2;
+ RSA *p3, *p4;
+#endif /* CRYPTO */
+ struct keynote_binary *bn1, *bn2;
+
+ if ((key1 == (void *) NULL) ||
+ (key2 == (void *) NULL))
+ return RESULT_FALSE;
+
+ switch (algorithm)
+ {
+ case KEYNOTE_ALGORITHM_NONE:
+ if (!strcmp((char *) key1, (char *) key2))
+ return RESULT_TRUE;
+ else
+ return RESULT_FALSE;
+
+ case KEYNOTE_ALGORITHM_DSA:
+#ifdef CRYPTO
+ p1 = (DSA *) key1;
+ p2 = (DSA *) key2;
+ if (!BN_cmp(p1->p, p2->p) &&
+ !BN_cmp(p1->q, p2->q) &&
+ !BN_cmp(p1->g, p2->g) &&
+ !BN_cmp(p1->pub_key, p2->pub_key))
+ return RESULT_TRUE;
+ else
+ return RESULT_FALSE;
+#else /* CRYPTO */
+ return RESULT_FALSE;
+#endif /* CRYPTO */
+
+ case KEYNOTE_ALGORITHM_RSA:
+#ifdef CRYPTO
+ p3 = (RSA *) key1;
+ p4 = (RSA *) key2;
+ if (!BN_cmp(p3->n, p4->n) &&
+ !BN_cmp(p3->e, p4->e))
+ return RESULT_TRUE;
+ else
+ return RESULT_FALSE;
+#else /* CRYPTO */
+ return RETURN_FALSE;
+#endif /* CRYPTO */
+
+ case KEYNOTE_ALGORITHM_ELGAMAL:
+ /* Not supported yet */
+ return RESULT_FALSE;
+
+ case KEYNOTE_ALGORITHM_PGP:
+ /* Not supported yet */
+ return RESULT_FALSE;
+
+ case KEYNOTE_ALGORITHM_BINARY:
+ bn1 = (struct keynote_binary *) key1;
+ bn2 = (struct keynote_binary *) key2;
+ if ((bn1->bn_len == bn2->bn_len) &&
+ !memcmp(bn1->bn_key, bn2->bn_key, bn1->bn_len))
+ return RESULT_TRUE;
+ else
+ return RESULT_FALSE;
+
+ default:
+ return RESULT_FALSE;
+ }
+}
+
+/*
+ * Verify the signature on an assertion; return SIGRESULT_TRUE is
+ * success, SIGRESULT_FALSE otherwise.
+ */
+int
+keynote_sigverify_assertion(struct assertion *as)
+{
+#if defined(CRYPTO) || defined(PGPLIB)
+ int hashtype, enc, intenc, alg = KEYNOTE_ALGORITHM_NONE, hashlen = 0;
+ unsigned char *sig, *decoded = (char *) NULL, *ptr;
+#ifdef CRYPTO
+ unsigned char res2[20];
+ SHA_CTX shscontext;
+ MD5_CTX md5context;
+ DSA *dsa;
+ RSA *rsa;
+ int len;
+#endif /* CRYPTO */
+ if ((as->as_signature == (char *) NULL) ||
+ (as->as_startofsignature == (char *) NULL) ||
+ (as->as_allbutsignature == (char *) NULL) ||
+ (as->as_allbutsignature - as->as_startofsignature <= 0))
+ return SIGRESULT_FALSE;
+
+ alg = keynote_get_sig_algorithm(as->as_signature, &hashtype, &enc,
+ &intenc);
+ if (alg == KEYNOTE_ALGORITHM_NONE)
+ return SIGRESULT_FALSE;
+
+ /* Check for matching algorithms */
+ if (alg != as->as_signeralgorithm)
+ return SIGRESULT_FALSE;
+
+ sig = index(as->as_signature, ':'); /* Move forward to the Encoding. We
+ * are guaranteed to have a ':'
+ * character, since this is a valid
+ * signature */
+ sig++;
+
+ switch (hashtype)
+ {
+ case KEYNOTE_HASH_SHA1:
+#ifdef CRYPTO
+ hashlen = 20;
+ memset(res2, 0, hashlen);
+ SHA1_Init(&shscontext);
+ SHA1_Update(&shscontext, as->as_startofsignature,
+ as->as_allbutsignature - as->as_startofsignature);
+ SHA1_Update(&shscontext, as->as_signature,
+ (char *) sig - as->as_signature);
+ SHA1_Final(res2, &shscontext);
+#endif /* CRYPTO */
+ break;
+
+ case KEYNOTE_HASH_MD5:
+#ifdef CRYPTO
+ hashlen = 16;
+ memset(res2, 0, hashlen);
+ MD5_Init(&md5context);
+ MD5_Update(&md5context, as->as_startofsignature,
+ as->as_allbutsignature - as->as_startofsignature);
+ MD5_Update(&md5context, as->as_signature,
+ (char *) sig - as->as_signature);
+ MD5_Final(res2, &md5context);
+#endif /* CRYPTO */
+ break;
+
+ case KEYNOTE_HASH_NONE:
+ break;
+ }
+
+ /* Remove ASCII encoding */
+ switch (enc)
+ {
+ case ENCODING_NONE:
+ ptr = (char *) NULL;
+ break;
+
+ case ENCODING_HEX:
+ len = strlen(sig) / 2;
+ if (kn_decode_hex(sig, (char **) &decoded) != 0)
+ return -1;
+ ptr = decoded;
+ break;
+
+ case ENCODING_BASE64:
+ len = strlen(sig);
+ if (len % 4) /* Base64 encoding must be a multiple of 4 */
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ len = 3 * (len / 4);
+ decoded = (unsigned char *) calloc(len, sizeof(unsigned char));
+ ptr = decoded;
+ if (decoded == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+
+ len = kn_decode_base64(sig, decoded, len);
+ if ((len == -1) || (len == 0) || (len == 1))
+ return -1;
+ break;
+
+ case ENCODING_NATIVE:
+ decoded = (unsigned char *) strdup(sig);
+ if (decoded == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return -1;
+ }
+ ptr = decoded;
+ break;
+
+ default:
+ keynote_errno = ERROR_SYNTAX;
+ return -1;
+ }
+
+ /* DSA */
+ if ((alg == KEYNOTE_ALGORITHM_DSA) && (intenc == INTERNAL_ENC_ASN1))
+ {
+ dsa = (DSA *) as->as_authorizer;
+ if (DSA_verify(0, res2, hashlen, decoded, len, dsa) == 1)
+ {
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+ return SIGRESULT_TRUE;
+ }
+ }
+ else /* RSA */
+ if ((alg == KEYNOTE_ALGORITHM_RSA) && (intenc == INTERNAL_ENC_PKCS1))
+ {
+ rsa = (RSA *) as->as_authorizer;
+ if (RSA_verify_ASN1_OCTET_STRING(RSA_PKCS1_PADDING, res2, hashlen,
+ decoded, len, rsa) == 1)
+ {
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+ return SIGRESULT_TRUE;
+ }
+ }
+ else
+ if ((alg == KEYNOTE_ALGORITHM_X509) && (intenc == INTERNAL_ENC_ASN1))
+ {
+ /* RSA-specific */
+ rsa = (RSA *) as->as_authorizer;
+ if (RSA_verify(NID_shaWithRSAEncryption, res2, hashlen, decoded,
+ len, rsa) == 1)
+ {
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+ return SIGRESULT_TRUE;
+ }
+ }
+
+ /* Handle more algorithms here */
+
+ if (ptr != (unsigned char *) NULL)
+ free(ptr);
+#endif /* CRYPTO || PGPLIB */
+
+ return SIGRESULT_FALSE;
+}
+
+/*
+ * Sign an assertion.
+ */
+static char *
+keynote_sign_assertion(struct assertion *as, char *sigalg, void *key,
+ int keyalg, int verifyflag)
+{
+#if defined(CRYPTO) || defined(PGPLIB)
+#ifdef CRYPTO
+ int slen, i, hashlen = 0, hashtype, alg, encoding, internalenc;
+ unsigned char *sig = (char *) NULL, *finalbuf = (char *) NULL;
+ unsigned char res2[LARGEST_HASH_SIZE], *sbuf = (char *) NULL;
+ BIO *biokey = (BIO *) NULL;
+ DSA *dsa = (DSA *) NULL;
+ RSA *rsa = (RSA *) NULL;
+ SHA_CTX shscontext;
+ MD5_CTX md5context;
+#endif /* CRYPTO */
+
+ if ((as->as_signature_string_s == (char *) NULL) ||
+ (as->as_startofsignature == (char *) NULL) ||
+ (as->as_allbutsignature == (char *) NULL) ||
+ (as->as_allbutsignature - as->as_startofsignature <= 0) ||
+ (as->as_authorizer == (void *) NULL) ||
+ (key == (void *) NULL) ||
+ (as->as_signeralgorithm == KEYNOTE_ALGORITHM_NONE))
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ alg = keynote_get_sig_algorithm(sigalg, &hashtype, &encoding,
+ &internalenc);
+ if ((alg != as->as_signeralgorithm) || (alg != keyalg))
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ sig = index(sigalg, ':');
+ if (sig == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ sig++;
+
+ switch (hashtype)
+ {
+ case KEYNOTE_HASH_SHA1:
+#ifdef CRYPTO
+ hashlen = 20;
+ memset(res2, 0, hashlen);
+ SHA1_Init(&shscontext);
+ SHA1_Update(&shscontext, as->as_startofsignature,
+ as->as_allbutsignature - as->as_startofsignature);
+ SHA1_Update(&shscontext, sigalg, (char *) sig - sigalg);
+ SHA1_Final(res2, &shscontext);
+#endif /* CRYPTO */
+ break;
+
+ case KEYNOTE_HASH_MD5:
+#ifdef CRYPTO
+ hashlen = 16;
+ memset(res2, 0, hashlen);
+ MD5_Init(&md5context);
+ MD5_Update(&md5context, as->as_startofsignature,
+ as->as_allbutsignature - as->as_startofsignature);
+ MD5_Update(&md5context, sigalg, (char *) sig - sigalg);
+ MD5_Final(res2, &md5context);
+#endif /* CRYPTO */
+ break;
+
+ case KEYNOTE_HASH_NONE:
+ break;
+ }
+
+#ifdef CRYPTO
+ if ((alg == KEYNOTE_ALGORITHM_DSA) &&
+ (hashtype == KEYNOTE_HASH_SHA1) &&
+ (internalenc == INTERNAL_ENC_ASN1) &&
+ ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64)))
+ {
+ dsa = (DSA *) key;
+ sbuf = (unsigned char *) calloc(DSA_size(dsa), sizeof(unsigned char));
+ if (sbuf == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (DSA_sign(0, res2, hashlen, sbuf, &slen, dsa) <= 0)
+ {
+ free(sbuf);
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+ }
+ else
+ if ((alg == KEYNOTE_ALGORITHM_RSA) &&
+ ((hashtype == KEYNOTE_HASH_SHA1) ||
+ (hashtype == KEYNOTE_HASH_MD5)) &&
+ (internalenc == INTERNAL_ENC_PKCS1) &&
+ ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64)))
+ {
+ rsa = (RSA *) key;
+ sbuf = (unsigned char *) calloc(RSA_size(rsa),
+ sizeof(unsigned char));
+ if (sbuf == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (RSA_sign_ASN1_OCTET_STRING(RSA_PKCS1_PADDING, res2, hashlen,
+ sbuf, &slen, rsa) <= 0)
+ {
+ free(sbuf);
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+ }
+ else
+ if ((alg == KEYNOTE_ALGORITHM_X509) &&
+ (hashtype == KEYNOTE_HASH_SHA1) &&
+ (internalenc == INTERNAL_ENC_ASN1))
+ {
+ if ((biokey = BIO_new(BIO_s_mem())) == (BIO *) NULL)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ if (BIO_write(biokey, key, strlen(key) + 1) <= 0)
+ {
+ BIO_free(biokey);
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ /* RSA-specific */
+ rsa = (RSA *) PEM_read_bio_RSAPrivateKey(biokey, NULL, NULL);
+ if (rsa == (RSA *) NULL)
+ {
+ BIO_free(biokey);
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ sbuf = calloc(RSA_size(rsa), sizeof(char));
+ if (sbuf == (unsigned char *) NULL)
+ {
+ BIO_free(biokey);
+ RSA_free(rsa);
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (RSA_sign(NID_shaWithRSAEncryption, res2, hashlen, sbuf, &slen,
+ rsa) <= 0)
+ {
+ BIO_free(biokey);
+ RSA_free(rsa);
+ free(sbuf);
+ keynote_errno = ERROR_SIGN_FAILURE;
+ return NULL;
+ }
+
+ BIO_free(biokey);
+ RSA_free(rsa);
+ }
+ else /* Other algorithms here */
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ /* ASCII encoding */
+ switch (encoding)
+ {
+ case ENCODING_HEX:
+ i = kn_encode_hex(sbuf, (char **) &finalbuf, slen);
+ free(sbuf);
+ if (i != 0)
+ return (char *) NULL;
+ break;
+
+ case ENCODING_BASE64:
+ finalbuf = (unsigned char *) calloc(2 * slen,
+ sizeof(unsigned char));
+ if (finalbuf == (unsigned char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ free(sbuf);
+ return (char *) NULL;
+ }
+
+ if ((slen = kn_encode_base64(sbuf, slen, finalbuf,
+ 2 * slen)) == -1)
+ {
+ free(sbuf);
+ return (char *) NULL;
+ }
+ break;
+
+ default:
+ free(sbuf);
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ /* Replace as->as_signature */
+ as->as_signature = (char *) calloc(strlen(sigalg) +
+ strlen(finalbuf) + 1, sizeof(char));
+ if (as->as_signature == (char *) NULL)
+ {
+ free(finalbuf);
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ /* Concatenate algorithm name and signature value */
+ sprintf(as->as_signature, "%s%s", sigalg, finalbuf);
+ free(finalbuf);
+ finalbuf = as->as_signature;
+
+ /* Verify the newly-created signature if requested */
+ if (verifyflag)
+ {
+ /* Do the signature verification */
+ if (keynote_sigverify_assertion(as) != SIGRESULT_TRUE)
+ {
+ as->as_signature = (char *) NULL;
+ free(finalbuf);
+ if (keynote_errno == 0)
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ as->as_signature = (char *) NULL;
+ }
+ else
+ as->as_signature = (char *) NULL;
+
+ /* Everything ok */
+ return (char *) finalbuf;
+#endif /* CRYPTO */
+#else /* CRYPTO || PGPLIB */
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+#endif /* CRYPTO || PGPLIB */
+}
+
+/*
+ * Verify the signature on an assertion.
+ */
+int
+kn_verify_assertion(char *buf, int len)
+{
+ struct assertion *as;
+ int res;
+
+ keynote_errno = 0;
+ as = keynote_parse_assertion(buf, len, ASSERT_FLAG_SIGVER);
+ if (as == (struct assertion *) NULL)
+ return -1;
+
+ res = keynote_sigverify_assertion(as);
+ keynote_free_assertion(as);
+ return res;
+}
+
+/*
+ * Produce the signature for an assertion.
+ */
+char *
+kn_sign_assertion(char *buf, int buflen, char *key, char *sigalg, int vflag)
+{
+ int i, alg, hashtype, encoding, internalenc;
+ struct keynote_deckey dc;
+ struct assertion *as;
+ char *s, *sig;
+
+ keynote_errno = 0;
+ s = (char *) NULL;
+
+ if ((sigalg == (char *) NULL) || (buf == (char *) NULL) ||
+ (key == (char *) NULL))
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return (char *) NULL;
+ }
+
+ if (sigalg[strlen(sigalg) - 1] != ':')
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ /* We're using a different format for X509 private keys, so... */
+ alg = keynote_get_sig_algorithm(sigalg, &hashtype, &encoding,
+ &internalenc);
+ if (alg != KEYNOTE_ALGORITHM_X509)
+ {
+ /* Parse the private key */
+ s = keynote_get_private_key(key);
+ if (s == (char *) NULL)
+ return (char *) NULL;
+
+ /* Decode private key */
+ i = kn_decode_key(&dc, s, KEYNOTE_PRIVATE_KEY);
+ if (i == -1)
+ {
+ free(s);
+ return (char *) NULL;
+ }
+ }
+ else /* X509 private key */
+ {
+ dc.dec_key = key;
+ dc.dec_algorithm = alg;
+ }
+
+ as = keynote_parse_assertion(buf, buflen, ASSERT_FLAG_SIGGEN);
+ if (as == (struct assertion *) NULL)
+ {
+ if (alg != KEYNOTE_ALGORITHM_X509)
+ {
+ keynote_free_key(dc.dec_key, dc.dec_algorithm);
+ free(s);
+ }
+ return (char *) NULL;
+ }
+
+ sig = keynote_sign_assertion(as, sigalg, dc.dec_key, dc.dec_algorithm,
+ vflag);
+ if (alg != KEYNOTE_ALGORITHM_X509)
+ keynote_free_key(dc.dec_key, dc.dec_algorithm);
+ keynote_free_assertion(as);
+ if (s != (char *) NULL)
+ free(s);
+ return sig;
+}
+
+/*
+ * ASCII-encode a key.
+ */
+char *
+kn_encode_key(struct keynote_deckey *dc, int iencoding,
+ int encoding, int keytype)
+{
+#ifdef CRYPTO
+ char *foo, *ptr;
+ DSA *dsa;
+ RSA *rsa;
+ int i;
+#endif /* CRYPTO */
+ struct keynote_binary *bn;
+ char *s;
+
+ keynote_errno = 0;
+ if ((dc == (struct keynote_deckey *) NULL) ||
+ (dc->dec_key == (void *) NULL))
+ {
+ keynote_errno = ERROR_NOTFOUND;
+ return (char *) NULL;
+ }
+
+#ifdef CRYPTO
+ /* DSA keys */
+ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_DSA) &&
+ (iencoding == INTERNAL_ENC_ASN1) &&
+ ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64)))
+ {
+ dsa = (DSA *) dc->dec_key;
+ if (keytype == KEYNOTE_PUBLIC_KEY)
+ i = i2d_DSAPublicKey(dsa, NULL);
+ else
+ i = i2d_DSAPrivateKey(dsa, NULL);
+
+ if (i <= 0)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ ptr = foo = (char *) calloc(i, sizeof(char));
+ if (foo == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ dsa->write_params = 1;
+ if (keytype == KEYNOTE_PUBLIC_KEY)
+ i2d_DSAPublicKey(dsa, (unsigned char **) &foo);
+ else
+ i2d_DSAPrivateKey(dsa, (unsigned char **) &foo);
+
+ if (encoding == ENCODING_HEX)
+ {
+ if (kn_encode_hex(ptr, &s, i) != 0)
+ {
+ free(ptr);
+ return (char *) NULL;
+ }
+
+ free(ptr);
+ return s;
+ }
+ else
+ if (encoding == ENCODING_BASE64)
+ {
+ s = (char *) calloc(2 * i, sizeof(char));
+ if (s == (char *) NULL)
+ {
+ free(ptr);
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (kn_encode_base64(ptr, i, s, 2 * i) == -1)
+ {
+ free(s);
+ free(ptr);
+ return (char *) NULL;
+ }
+
+ free(ptr);
+ return s;
+ }
+ }
+
+ /* RSA keys */
+ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_RSA) &&
+ (iencoding == INTERNAL_ENC_PKCS1) &&
+ ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64)))
+ {
+ rsa = (RSA *) dc->dec_key;
+ if (keytype == KEYNOTE_PUBLIC_KEY)
+ i = i2d_RSAPublicKey(rsa, NULL);
+ else
+ i = i2d_RSAPrivateKey(rsa, NULL);
+
+ if (i <= 0)
+ {
+ keynote_errno = ERROR_SYNTAX;
+ return (char *) NULL;
+ }
+
+ ptr = foo = (char *) calloc(i, sizeof(char));
+ if (foo == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (keytype == KEYNOTE_PUBLIC_KEY)
+ i2d_RSAPublicKey(rsa, (unsigned char **) &foo);
+ else
+ i2d_RSAPrivateKey(rsa, (unsigned char **) &foo);
+
+ if (encoding == ENCODING_HEX)
+ {
+ if (kn_encode_hex(ptr, &s, i) != 0)
+ {
+ free(ptr);
+ return (char *) NULL;
+ }
+
+ free(ptr);
+ return s;
+ }
+ else
+ if (encoding == ENCODING_BASE64)
+ {
+ s = (char *) calloc(2 * i, sizeof(char));
+ if (s == (char *) NULL)
+ {
+ free(ptr);
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (kn_encode_base64(ptr, i, s, 2 * i) == -1)
+ {
+ free(s);
+ free(ptr);
+ return (char *) NULL;
+ }
+
+ free(ptr);
+ return s;
+ }
+ }
+#endif /* CRYPTO */
+
+ /* BINARY keys */
+ if ((dc->dec_algorithm == KEYNOTE_ALGORITHM_BINARY) &&
+ (iencoding == INTERNAL_ENC_NONE) &&
+ ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64)))
+ {
+ bn = (struct keynote_binary *) dc->dec_key;
+
+ if (encoding == ENCODING_HEX)
+ {
+ if (kn_encode_hex(bn->bn_key, &s, bn->bn_len) != 0)
+ return (char *) NULL;
+
+ return s;
+ }
+ else
+ if (encoding == ENCODING_BASE64)
+ {
+ s = (char *) calloc(2 * bn->bn_len, sizeof(char));
+ if (s == (char *) NULL)
+ {
+ keynote_errno = ERROR_MEMORY;
+ return (char *) NULL;
+ }
+
+ if (kn_encode_base64(bn->bn_key, bn->bn_len, s,
+ 2 * bn->bn_len) == -1)
+ {
+ free(s);
+ return (char *) NULL;
+ }
+
+ return s;
+ }
+ }
+
+ keynote_errno = ERROR_NOTFOUND;
+ return (char *) NULL;
+}
diff --git a/lib/libkeynote/signature.h b/lib/libkeynote/signature.h
new file mode 100644
index 00000000000..d2f8faae092
--- /dev/null
+++ b/lib/libkeynote/signature.h
@@ -0,0 +1,64 @@
+/* $OpenBSD: signature.h,v 1.1 1999/05/23 22:11:06 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
+ * in April-May 1998
+ *
+ * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef __SIGNATURE_H__
+#define __SIGNATURE_H__
+
+#define KEYNOTE_HASH_NONE 0
+#define KEYNOTE_HASH_SHA1 1
+#define KEYNOTE_HASH_MD5 2
+
+#define DSA_HEX "dsa-hex:"
+#define DSA_HEX_LEN strlen(DSA_HEX)
+#define DSA_BASE64 "dsa-base64:"
+#define DSA_BASE64_LEN strlen(DSA_BASE64)
+#define RSA_PKCS1_HEX "rsa-hex:"
+#define RSA_PKCS1_HEX_LEN strlen(RSA_PKCS1_HEX)
+#define RSA_PKCS1_BASE64 "rsa-base64:"
+#define RSA_PKCS1_BASE64_LEN strlen(RSA_PKCS1_BASE64)
+#define ELGAMAL_HEX "elgamal-hex:"
+#define ELGAMAL_HEX_LEN strlen(ELGAMAL_HEX)
+#define ELGAMAL_BASE64 "elgamal-base64:"
+#define ELGAMAL_BASE64_LEN strlen(ELGAMAL_BASE64)
+#define PGP_NATIVE "pgp:"
+#define PGP_NATIVE_LEN strlen(PGP_NATIVE)
+#define BINARY_BASE64 "binary-base64:"
+#define BINARY_BASE64_LEN strlen(BINARY_BASE64)
+#define BINARY_HEX "binary-hex:"
+#define BINARY_HEX_LEN strlen(BINARY_HEX)
+#define X509_BASE64 "x509-base64:"
+#define X509_BASE64_LEN strlen(X509_BASE64)
+#define X509_HEX "x509-hex:"
+#define X509_HEX_LEN strlen(X509_HEX)
+
+#define KEYNOTE_PRIVATE_KEY_PREFIX "private-"
+#define KEYNOTE_PRIVATE_KEY_PREFIX_LEN strlen(KEYNOTE_PRIVATE_KEY_PREFIX)
+
+#define LARGEST_HASH_SIZE 20 /* In bytes, length of SHA1 hash */
+
+#include "assertion.h"
+
+int keynote_get_key_algorithm(char *, int *, int *);
+int keynote_sigverify_assertion(struct assertion *);
+int keynote_keycompare(void *, void *, int);
+void keynote_free_key(void *, int);
+#endif /* __SIGNATURE_H__ */
diff --git a/lib/libkeynote/testsuite/auth1 b/lib/libkeynote/testsuite/auth1
new file mode 100644
index 00000000000..b9383732201
--- /dev/null
+++ b/lib/libkeynote/testsuite/auth1
@@ -0,0 +1 @@
+KeyC # Some key
diff --git a/lib/libkeynote/testsuite/auth2 b/lib/libkeynote/testsuite/auth2
new file mode 100644
index 00000000000..bb700d8069e
--- /dev/null
+++ b/lib/libkeynote/testsuite/auth2
@@ -0,0 +1 @@
+KeyE
diff --git a/lib/libkeynote/testsuite/auth3 b/lib/libkeynote/testsuite/auth3
new file mode 100644
index 00000000000..e79e63561ec
--- /dev/null
+++ b/lib/libkeynote/testsuite/auth3
@@ -0,0 +1 @@
+Key12
diff --git a/lib/libkeynote/testsuite/auth4 b/lib/libkeynote/testsuite/auth4
new file mode 100644
index 00000000000..776d0fb609d
--- /dev/null
+++ b/lib/libkeynote/testsuite/auth4
@@ -0,0 +1,11 @@
+ # Comments are allowed
+ "dsa-hex:3081df02410082b9dc3a9671aa7f7595f15987a9\
+ f9a9d0fbe23540d193c342469fc7076fb71a5ef0abdd67e5f\
+ ad884862ae62b1fcf5a89c99e060b16b80b2c0b07ffb9dc66\
+ 79024100c9d63ddc7384f4c2ed0f0c8c40464faded1ae5636\
+ 4e48c7c199ab063e29834b54a9d2f6f37b17b2e62f54ce034\
+ 659c80968a46a22ca0414d417b5991e4b74727021500e3ec7\
+ 2171b4c535b0d967b0ce3eb5e7dbfd8d96302403097f8ce26\
+ 22ff8a4bcb8f74df518a92aa22efd6439415ed657253f5748\
+ 2eda35835b8976720b60690f7a6206529c69bf89af4acd0a9\
+ 017e541a12a5c366619f"
diff --git a/lib/libkeynote/testsuite/test-assertion1 b/lib/libkeynote/testsuite/test-assertion1
new file mode 100644
index 00000000000..2e9b9c167a1
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-assertion1
@@ -0,0 +1,45 @@
+keynote-version: 2 # some comment
+comment: The weird looking string test in the conditions field is for
+ verifying correctness of string grammar
+# comment inside comment field, no problem
+#authorizer: $$$$foo # Don't try this at home
+authorizer: "POLICY"
+licensees: (MYKEY) && ((("Key3") || "Key4") && (MYKEY)) || TWOKEY
+local-constants: MYKEY = "Key3"
+# we can put a comment here
+ TWOKEY = "dsa-hex:3081de02402ae5e2d8c12fbaec4934dd5a98cbe39159\
+ f1b8d02143a5e3d07c96c0acedef73d508a54286bb19b53cd2b7\
+ bd0beca47b12ec75ddd7a7aeece8b724fbf940ca220241008cfe\
+ 2799793dc5eef44cc78228d2a42e76246326e6f442d7c14eb705\
+ 3e48d49a001350177e7d320d762d87f10ecbeceffb12b359e4c0\
+ f827e05b34ef336823710215008773db9f8a9d42e7ad53c023d1\
+ 61dda43ae081a9024069f506a956d69c8a0a2ab6d6a888f57dd0\
+ 6593f537135b6d3c2bc928634f7e5e03b12c9fbac7ce4a6ce708\
+ b63bdcda576e5eeecfb68930a5c3ca8df71d84fd0e"
+conditions: app_domain == "testing" ->
+# gratuitous comment
+ {
+ 1 / 0 == 1 -> "true"; # runtime exception
+ true -> "false";
+ request == "whatever" -> "false";
+ TWOKEY == "dsa-hex:3081de02402ae5e2d8c12fbaec4934dd5a98cbe39159\
+ f1b8d02143a5e3d07c96c0acedef73d508a54286bb19b53cd2b7\
+ bd0beca47b12ec75ddd7a7aeece8b724fbf940ca220241008cfe\
+ 2799793dc5eef44cc78228d2a42e76246326e6f442d7c14eb705\
+ 3e48d49a001350177e7d320d762d87f10ecbeceffb12b359e4c0\
+ f827e05b34ef336823710215008773db9f8a9d42e7ad53c023d1\
+ 61dda43ae081a9024069f506a956d69c8a0a2ab6d6a888f57dd0\
+ 6593f537135b6d3c2bc928634f7e5e03b12c9fbac7ce4a6ce708\
+ b63bdcda576e5eeecfb68930a5c3ca8df71d84fd0e" &&
+ @(foo) == @foo &&
+ "this string contains a newline\n\
+ \ followed by one space." ==
+ "this\ string\ contains\ a\ newline\n\ foll\
+ owed\ by\ one\ space\." &&
+ "this string contains a newline\n\ \
+ followed by one space." ==
+ "this string contains a newline\012\040followed by one space." &&
+ request == "test" -> "true"; # this is another comment
+ request == "whatever3" -> "true";
+ request == "test" -> "fa" . "lse";
+ };
diff --git a/lib/libkeynote/testsuite/test-assertion2 b/lib/libkeynote/testsuite/test-assertion2
new file mode 100644
index 00000000000..66e6d8714ab
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-assertion2
@@ -0,0 +1,7 @@
+keynote-version: 2
+Comment: this policy will be false
+authorizer: "POLICY"
+licensees: "Key10"
+conditions: app_domain == "testing" && request == "test" &&
+ variable == "no" -> "true";
+ true -> "false";
diff --git a/lib/libkeynote/testsuite/test-assertion3 b/lib/libkeynote/testsuite/test-assertion3
new file mode 100644
index 00000000000..ac7a200e9a0
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-assertion3
@@ -0,0 +1,8 @@
+keynote-version: 2
+authorizer: "Key3"
+# This assertion will return "true"
+licensees: 2-of("Key5", "Key6", "Key7", "KeyE")
+conditions: app_domain == "testing" && request == "test" &&
+ foo == "bar" && $("foo") == "bar" &&
+ $(foo) == "xyz" && $foo == "xyz" && $$foo == "qua" &&
+ variable == "yes" -> "true";
diff --git a/lib/libkeynote/testsuite/test-assertion4 b/lib/libkeynote/testsuite/test-assertion4
new file mode 100644
index 00000000000..b379203d5ca
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-assertion4
@@ -0,0 +1,5 @@
+keynote-version: 2
+authorizer: "Key4"
+licensees: "Key8"
+conditions: app_domain == "testing" && request == "test" &&
+ variable == "yes" -> "true";
diff --git a/lib/libkeynote/testsuite/test-assertion5 b/lib/libkeynote/testsuite/test-assertion5
new file mode 100644
index 00000000000..7ca4cad5b8c
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-assertion5
@@ -0,0 +1,12 @@
+keynote-version: 2
+authorizer: "Key5"
+licensees: "Key6"
+# this assertion will evaluate to "false" because of the conditions field value
+conditions: app_domain == "testing" && request == "test" &&
+ variable == "no" -> "true"; # this clause won't match
+ app_domain == "testing" -> {
+ app_domain == "testing" -> "false"; # this will match
+ var == "no" -> { foo == "bar" ->
+ "false"; # this won't match
+ };
+ };
diff --git a/lib/libkeynote/testsuite/test-assertion6 b/lib/libkeynote/testsuite/test-assertion6
new file mode 100644
index 00000000000..a1b8a59ebc4
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-assertion6
@@ -0,0 +1,7 @@
+keynote-version: 2
+authorizer: "Key6"
+licensees: "KeyB" # this assertion will return "false" because
+# of the licensees field
+conditions: app_domain == "testing" && request == "test" &&
+ (variable == "no" || variable == "yes") -> "true";
+# however, the conditions field will return "true"
diff --git a/lib/libkeynote/testsuite/test-assertion7 b/lib/libkeynote/testsuite/test-assertion7
new file mode 100644
index 00000000000..1860d9117dc
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-assertion7
@@ -0,0 +1,24 @@
+comment: this assertion will return "true", since "KeyC" is among the
+ action authorizers and the conditions field will return "true"
+authorizer: "Key6"
+licensees: "KeyC"
+conditions: app_domain == "testing" && request == "test" &&
+ _VALUES == "false,maybe,probably,true" && _VALUES != "foo" &&
+ _ACTION_AUTHORIZERS ~= "(.*,)KeyE,.*" &&
+ @ _0 == 2^2/4 && # minor regexp testing here
+ _ACTION_AUTHORIZERS != "foo" &&
+ # now let's test precedence rules
+ $foo . bar == ($foo) . bar &&
+ $foo . bar != $(foo . bar) &&
+ $foo == $(foo) &&
+ $ ("fo" . "o") == foo &&
+ $ "fo" . "o" != $"foo" &&
+ -1 * 12 == -12 &&
+ 12 * 1 - 1 != 0 &&
+ @(foo . bar) == 0 &&
+ $((("foo"))) == foo &&
+ @foo + 1 == @bar + 1 && # 1 == 1
+ @foo == 0 &&
+ variable == "yes" -> "true";
+
+ @foo / @foo == @foo -> "maybe";
diff --git a/lib/libkeynote/testsuite/test-env b/lib/libkeynote/testsuite/test-env
new file mode 100644
index 00000000000..9151c36da66
--- /dev/null
+++ b/lib/libkeynote/testsuite/test-env
@@ -0,0 +1,10 @@
+# Comments are allowed
+app_domain = "test\
+ in\g"
+request = test
+variable = yes
+weirduse = POLICY
+foo = bar
+bar = xyz
+xyz = qua
+qua = weirduse