cookie. Add manual pages.
## -*-m4-*-
##
-## $Id: Makefile.m4,v 1.83 2004/04/21 00:37:32 mdw Exp $
+## $Id$
##
## Makefile for Catacomb
##
## --- Utility programs ---
bin_PROGRAMS = \
- dsig key pixie rspit factorial hashsum mkphrase catcrypt
+ dsig key pixie cookie rspit factorial hashsum mkphrase catcrypt
+noinst_LIBRARIES = libcatcrypt.a
bin_SCRIPTS = catacomb-config xpixie
noinst_PROGRAMS = \
genprimes mptypes serpent-check bittest mpdump \
perftest \
addsuffix(`gen_tables', `-mktab')
-LDADD = libcatacomb.la
-
-dsig_SOURCES = dsig.c cc.h cc-sig.c getdate.y getdate.h
-catcrypt_SOURCES = catcrypt.c cc.h cc-sig.c cc-kem.c cc-enc.c
-key_SOURCES = keyutil.c getdate.y getdate.h
+LDADD = libcatacomb.la libcatcrypt.a
+
+libcatcrypt_a_SOURCES = \
+ cc.h getdate.h \
+ cc-sig.c cc-subcmd.c cc-enc.c cc-kem.c cc-list.c \
+ getdate.y
+
+dsig_SOURCES = dsig.c
+cookie_SOURCES = cookie.c
+catcrypt_SOURCES = catcrypt.c
+key_SOURCES = keyutil.c
hashsum_SOURCES = hashsum.c
rspit_SOURCES = rspit.c
factorial_SOURCES = factorial.c
## --- Documentation ---
-man_MANS = key.1 hashsum.1 keyring.5 pixie.1
+man_MANS = key.1 dsig.1 cookie.1 catcrypt.1 hashsum.1 keyring.5 pixie.1
## --- Other handy definitions ---
--- /dev/null
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.ie t \{\
+. if \n(.g \{\
+. fam P
+. \}
+.\}
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t .ds o \(bu
+.el .ds o o
+.TH catcrypt 1 "30 September 2004" "Straylight/Edgeware" "Catacomb cryptographic library"
+.SH NAME
+catcrypt \- encrypt and decrypt messages
+.SH SYNOPSIS
+.B catcrypt
+.RB [ \-k
+.IR keyring ]
+.I command
+.PP
+where
+.I command
+is one of:
+.PP
+.B help
+.RI [ command ...]
+.br
+.B show
+.RI [ item ...]
+.br
+.B encrypt
+.RB [ \-a ]
+.RB [ \-k
+.IR tag ]
+.RB [ \-f
+.IR format ]
+.RB [ \-o
+.IR output ]
+.RI [ file ]
+.br
+.B decrypt
+.RB [ \-aqv ]
+.RB [ \-f
+.IR format ]
+.RB [ \-o
+.IR output ]
+.RI [ file ]
+.br
+.B encode
+.RB [ \-f
+.IR format ]
+.RB [ \-b
+.IR boundary ]
+.RB [ \-o
+.IR output ]
+.RI [ file ]
+.br
+.B encode
+.RB [ \-f
+.IR format ]
+.RB [ \-b
+.IR boundary ]
+.RB [ \-o
+.IR output ]
+.RI [ file ]
+.SH "DESCRIPTION"
+The
+.B catcrypt
+command encrypts and decrypts messages. It also works as a simple PEM
+encoder and decoder. It provides a number of subcommands, by which the
+various operations may be carried out.
+.SS "Global options"
+Before the command name,
+.I "global options"
+may be given. The following global options are supported:
+.TP
+.BR "\-h, \-\-help " [ \fIcommand ...]
+Writes a brief summary of
+.BR catcrypt 's
+various options to standard output, and returns a successful exit
+status. With command names, gives help on those commands.
+.TP
+.B "\-v, \-\-version"
+Writes the program's version number to standard output, and returns a
+successful exit status.
+.TP
+.B "\-u, \-\-usage"
+Writes a very terse command line summary to standard output, and returns
+a successful exit status.
+.TP
+.BI "\-k, \-\-keyring " file
+Names the keyring file which
+.B key
+is to process. The default keyring, used if this option doesn't specify
+one, is the file named
+.B keyring
+in the current directory. See
+.BR key (1)
+and
+.BR keyring (5)
+for more details about keyring files.
+.SH "KEY SETUP"
+Algorithms to be used with a particular key are described by attributes
+on the key, or its type. The
+.B catcrypt
+command deals with both signing and key-encapsulation keys.
+.SS "Key-encapsulation keys"
+(Key encapsulation is a means of transmitting a short, known, random
+secret to a recipient. It differs from encryption in technical ways
+which are largely uninteresting at this point.)
+.PP
+A
+.I kemalgspec
+has the syntax
+.IR kem \c
+.RB [ / \c
+.IR cipher \c
+.RB [ / \c
+.IR hash ]].
+If a
+.B kem
+attribute is present on the key, then it must have this form; otherwise,
+the key's type must have the form
+.BR cckem- \c
+.IR kemalgspec .
+Algorithm selections are taken from appropriately-named attributes, or,
+failing that, from the
+.IR kemalgspec .
+.PP
+The key-encapsulation mechanism is chosen according to the setting of
+.I kem
+as follows. Run
+.B catcrypt show kem
+for a list of supported KEMs.
+.TP
+.B rsa
+This is Shoup's RSA-KEM (formerly Simple RSA); see
+.I
+A proposal for an ISO standard for public key encryption (version 2.0)
+available at
+.BR http://eprint.iacr.org/2000/060/ .
+Use the
+.B rsa
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B dh
+This is standard Diffie-Hellman key exchange, hashing the resulting
+shared secret to form the key, as used in, e.g., DLIES (P1363a).
+Use the
+.B dh
+algorithm of the
+.B key add
+command, preferably with the
+.B \-LS
+options, to generate the key.
+.TP
+.B ec
+This is the elliptic-curve analogue of
+.BR dh . Use the
+.B ec
+algorithm of the
+.BR key (1))
+command to generate the key.
+.PP
+As well as the KEM itself, a number of supporting algorithms are used.
+These are taken from appropriately named attributes on the key or,
+failing that, derived from other attributes as described below.
+.TP
+.B cipher
+This is the symmetric encryption algorithm used for bulk data
+encryption. If there is no
+.B cipher
+attribute then the
+.I cipher
+in the
+.I kemalgspec
+is used; if that it absent, then the default of
+.B blowfish-cbc
+is used. Run
+.B catcrypt show cipher
+for a list of supported symmetric encryption algorithms.
+.TP
+.B hash
+This is the hash function used to distil entropy from the shared secret
+constructed by the raw KEM. If there is no
+.B hash
+attribute then the
+.I hash
+in the
+.I kemalgspec is used; if that is absent then the default of
+.B rmd160
+is used. Run
+.B catcrypt show hash
+for a list of supported symmetric encryption algorithms.
+.TP
+.B mac
+This is the message authentication algorithm used during bulk data
+encryption to ensure integrity of the encrypted message and defend
+against chosen-ciphertext attacks. If there is no
+.B mac
+attribute then
+.IB hash -hmac
+is chosen as a default. Run
+.B catcrypt show mac
+for a list of supported message authentication algorithms.
+.TP
+.B kdf
+This is the key derivation function used to stretch the hashed shared
+secret to a sufficient length to select symmetric encryption and
+authentication keys, initialization vectors and other necessary
+pseudorandom quantities. If there is no
+.B kdf
+attribute then
+.IB hash -mgf
+is chosen as a default. Run
+.B catcrypt show kdf
+for a list of supported key derivation functions.
+.B Caution!
+Not all supported functions have the required security features: don't
+override the default choice unless you know what you're doing.
+.SS "Signing keys"
+A
+.I sigalgspec
+has the form
+.IR sig \c
+.RB [ / \c
+.IR hash ].
+If a
+.B sig
+attribute is present on the key, then it must have this form; otherwise,
+the key's type must have the form
+.BI ccsig- \c
+.IR sigalgspec .
+Algorithm selections are taken from appropriately-named attributes, or,
+failing that, from the
+.IR sigalgspec .
+.PP
+The signature algorithm is chosen according to the setting of
+.I sig
+as follows. Run
+.B catcrypt show sig
+for a list of supported signature algorithms.
+.TP
+.B rsapkcs1
+This is almost the same as the RSASSA-PKCS1-v1_5 algorithm described in
+RFC3447; the difference is that the hash is left bare rather than being
+wrapped in a DER-encoded
+.B DigestInfo
+structure. This doesn't affect security since the key can only be used
+with the one hash function anyway, and dropping the DER wrapping permits
+rapid adoption of new hash functions. Regardless, use of this algorithm
+is not recommended, since the padding method has been shown vulnerable
+to attack. Use the
+.B rsa
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B rsapss
+This is the RSASSA-PSS algorithm described in RFC3447. It is the
+preferred RSA-based signature scheme. Use the
+.B rsa
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B dsa
+This is the DSA algorithm described in FIPS180-1 and FIPS180-2. Use the
+.B dsa
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B ecdsa
+This is the ECDSA algorithm described in ANSI X9.62 and FIPS180-2. Use
+the
+.B ec
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B kcdsa
+This is the revised KCDSA (Korean Certificate-based Digital Signature
+Algorithm) described in
+.I The Revised Version of KCDSA
+.RB ( http://dasan.sejong.ac.kr/~chlim/pub/kcdsa1.ps ).
+Use the
+.B dh
+algorithm of the
+.B key add
+command with the
+.B \-LS
+options (see
+.BR key (1))
+to generate the key.
+.TP
+.B eckcdsa
+This is an unofficial elliptic-curve analogue of the KCDSA algorithm.
+Use the
+.B ec
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.PP
+As well as the signature algorithm itself, a hash function is used.
+This is taken from the
+.B hash
+attribute on the key, or, failing that, from the
+.I hash
+specified in the
+.IR sigalgspec ,
+or, if that is absent, determined by the signature algorithm as follows.
+.hP \*o
+For
+.BR rsapkcs1 ,
+.BR rsapss ,
+.BR dsa ,
+and
+.BR ecdsa ,
+the default hash function is
+.BR sha .
+.hP \*o
+For
+.BR kcdsa
+and
+.BR eckcdsa ,
+the default hash function is
+.BR has160 .
+.PP
+Run
+.B catcrypt show hash
+for a list of supported hash functions.
+.SH "ENCODINGS"
+Two encodings for the ciphertext are supported.
+.TP
+.B binary
+The raw format, which has the benefit of being smaller, but needs to be
+attached to mail messages and generally handled with care.
+.TP
+.B pem
+PEM-encapsulated Base-64 encoded text. This format can be included
+directly in email and picked out again automatically; but there is a
+4-to-3 data expansion as a result.
+.SH "COMMAND REFERENCE"
+.SS help
+The
+.B help
+command behaves exactly as the
+.B \-\-help
+option. With no arguments, it shows an overview of
+.BR catcrypt 's
+options; with arguments, it describes the named subcommands.
+.SS show
+The
+.B show
+command prints various lists of tokens understood by
+.BR catcrypt .
+With no arguments, it prints all of the lists; with arguments, it prints
+just the named lists, in order. The recognized lists can be enumerated
+using the
+.VS
+catcrypt show list
+.VE
+command. The lists are as follows.
+.TP
+.B list
+The lists which can be enumerated by the
+.B show
+command.
+.TP
+.B kem
+The key-encapsulation algorithms which can be used in a
+key-encapsulation key's
+.B kem
+attribute.
+.TP
+.B cipher
+The symmetric encryption algorithms which can be used in a
+key-encapsulation key's
+.B cipher
+attribute.
+.TP
+.B mac
+The message authentication algorithms which can be used in a
+key-encapsulation key's
+.B mac
+attribute.
+.TP
+.B sig
+The signature algorithms which can be used in a signing key's
+.B sig
+attribute.
+.TP
+.B hash
+The hash functions which can be used in a key's
+.B hash
+attribute.
+.TP
+.B enc
+The encodings which can be applied to encrypted messages; see
+.B ENCODINGS
+above.
+.SS encrypt
+The
+.B encrypt
+command encrypts a file and writes out the appropriately-encoded
+ciphertext. By default, it reads from standard input and writes to
+standard output. If a filename argument is given, this file is read
+instead (as binary data).
+.PP
+The following options are recognized.
+.TP
+.B "\-a, \-\-armour"
+Produce ASCII-armoured output. This is equivalent to specifying
+.BR "\-f pem" .
+The variant spelling
+.B "\-\-armor"
+is also accepted.
+.TP
+.BI "\-f, \-\-format " format
+Produce output encoded according to
+.IR format .
+.TP
+.BI "\-k, \-\-key " tag
+Use the key-encapsulation key named
+.I tag
+in the current keyring; the default key is
+.BR ccrypt .
+.TP
+.BI "\-s, \-\-sign-key " tag
+Use the signature key named
+.I tag
+in the current keyring; the default is not to sign the ciphertext.
+.TP
+.BI "\-o, \-\-ouptut " file
+Write output to
+.I file
+rather than to standard output.
+.SS decrypt
+The
+.B decrypt
+command decrypts a ciphertext and writes out the plaintext. By default,
+it reads from standard input and writes to standard output. If a
+filename argument is given, this file is read instead.
+.PP
+The following options are recognized.
+.TP
+.B "\-a, \-\-armour"
+Read ASCII-armoured output. This is equivalent to specifying
+.BR "\-f pem" .
+The variant spelling
+.B "\-\-armor"
+is also accepted.
+.TP
+.BI "\-f, \-\-format " format
+Read input encoded according to
+.IR format .
+.TP
+.B "\-v, \-\-verbose"
+Produce more verbose messages. See below for the messages produced
+during decryption. The default verbosity level is 1. (Currently this
+is the most verbose setting. This might not be the case always.)
+.TP
+.B "\-q, \-\-quiet"
+Produce fewer messages.
+.TP
+.BI "\-o, \-\-output " file
+Write output to
+.I file
+instead of to standard output. The file is written in binary mode.
+Fixing line-end conventions is your problem; there are lots of good
+tools for dealing with it.
+.PP
+Output is written to standard output in a machine-readable format.
+Major problems cause the program to write a diagnostic to standard error
+and exit nonzero as usual. The quantity of output varies depending on
+the verbosity level and whether the plaintext is also being written to
+standard output. Output lines begin with a keyword.:
+.TP
+.BI "FAIL " reason
+An error prevented decryption. The program will exit nonzero.
+.TP
+.BI "WARN " reason
+.B catcrypt
+encountered a situation which may or may not invalidate the decryption.
+.TP
+.BI "OK " message
+Decryption was successful. This is only produced if main output is
+being sent somewhere other than standard output.
+.TP
+.B "DATA"
+The plaintext follows, starting just after the next newline character or
+sequence. This is only produced if main output is being sent to
+standard output. If anything goes wrong, a
+.B FAIL
+message is printed, preceded and followed by a newline, and the program
+exits nonzero.
+.TP
+.BI "INFO " note
+Any other information.
+.PP
+The information written at the various verbosity levels is as follows.
+.hP 0.
+No output. Watch the exit status.
+.hP 1.
+All messages.
+.PP
+.B Warning!
+All output written has been checked for authenticity. However, since
+the input is chunked, a chunk will be checked and written before the
+authenticity of following chunks is established. Don't rely on the
+output being complete until
+.B catcrypt decrypt
+prints
+.B OK
+and/or exits successfully.
+.SS "encode"
+The
+.B encode
+command encodes an input file according to one of the encodings
+described above in
+.BR ENCODINGS .
+The input is read from the
+.I file
+given on the command line, or from standard input if none is specified.
+Options provided are:
+.TP
+.BI "\-f, \-\-format " format
+Produce output in
+.IR format .
+Run
+.B catcrypt show enc
+for a list of encoding formats.
+.TP
+.BI "\-b, \-\-boundary " label
+Set the PEM boundary string to
+.IR label ;
+i.e., assuming we're encoding in PEM format, the output will have
+.BI "\-\-\-\-\-BEGIN " label "\-\-\-\-\-"
+at the top and
+.BI "\-\-\-\-\-END " label "\-\-\-\-\-"
+at the bottom. The default
+.I label
+is
+.BR MESSAGE .
+.TP
+.BI "\-o, \-\-output " file
+Write output to
+.I file
+instead of to standard output.
+.SS "decode"
+The
+.B decode
+command decodes an input file encoded according to one of the encodings
+described above in
+.BR ENCODINGS .
+The input is read from the
+.I file
+given on the command line, or from standard input if none is specified.
+Options provided are:
+.TP
+.BI "\-f, \-\-format " format
+Decode input in
+.IR format .
+Run
+.B catcrypt show enc
+for a list of encoding formats.
+.TP
+.BI "\-b, \-\-boundary " label
+Set the PEM boundary string to
+.IR label ;
+i.e., assuming we're encoding in PEM format, start processing input
+between
+.BI "\-\-\-\-\-BEGIN " label "\-\-\-\-\-"
+and
+.BI "\-\-\-\-\-END " label "\-\-\-\-\-"
+lines. Without this option,
+.B catcrypt
+will start reading at the first plausible boundary string, and continue
+processing until it reaches the matching end boundary.
+.TP
+.BI "\-o, \-\-output " file
+Write output to
+.I file
+instead of to standard output.
+.SH "SECURITY PROPERTIES"
+Assuming the security of the underlying primitive algorithms, the
+following security properties of the ciphertext hold.
+.hP \*o
+An adversary given the public key-encapsulation key and capable of
+requesting encryption of arbitrary plaintexts of his own devising is
+unable to decide whether he is given ciphertexts corresponding to his
+chosen plaintexts or random plaintexts of the same length. This holds
+even if the adversary is permitted to request decryption of any
+ciphertext other than one produced as a result of an encryption request.
+This property is called
+.BR IND-CCA2 .
+.hP \*o
+An adversary given the public key-encapsulation and verification keys,
+and capable of requesting encryption of arbitrary plaintext of his own
+devising is unable to produce a new ciphertext which will be accepted as
+genuine. This property is called
+.BR INT-CTXT .
+.hP \*o
+An adversary given the public key-encapsulation and verification keys,
+and capable of requesting encryption of arbitrary plaintext of his own
+devising is unable to decide whether the ciphertexts he is given are
+correctly signed. This property doesn't seem to have a name.
+.PP
+Not all is rosy. If you leak intermediate values during decryption then
+an adversary can construct a new correctly-signed message. Don't do
+that, then \(en leaking intermediate values often voids security
+warranties. But it does avoid the usual problem with separate signing
+and encryption that a careful leak by the recipient can produce evidence
+that you signed some incriminating message.
+.SH "CRYPTOGRAPHIC THEORY"
+Encryption of a message proceeds as follows.
+.hP 0.
+Emit a header packet containing the key-ids for the key-encapsulation
+key, and signature key if any.
+.hP 1.
+Use the KEM to produce a public value and a shared secret the recipient
+will be able to extract from the public value using his private key.
+Emit a packet containing the public value.
+.hP 2.
+Hash the shared secret. Use the KDF to produce a pseudorandom keystream
+of indefinite length.
+.hP 3.
+Use the first bits of the keystream to key a symmetric encryption
+scheme; use the next bits to key a message authentication code.
+.hP 4.
+If we're signing the message then extract 1024 bytes from the keystream,
+sign them, and emit a packet containing the signature. The signature
+packet doesn't contain the signed message, just the signature.
+.hP 5.
+Split the message into blocks. For each block, pick a random IV from
+the keystream, encrypt the block and emit a packet containing the
+IV, ciphertext and a MAC tag.
+.PP
+That's it. Nothing terribly controversial, really.
+.SH "SEE ALSO"
+.BR key (1),
+.BR dsig (1),
+.BR hashsum (1),
+.BR keyring (5).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
/* -*-c-*-
*
- * $Id: catcrypt.c,v 1.2 2004/05/09 13:03:46 mdw Exp $
+ * $Id$
*
* Command-line encryption tool
*
#include "key.h"
#include "cc.h"
+#include "ectab.h"
+#include "ptab.h"
+
/*----- Utilities ---------------------------------------------------------*/
/* --- @keyreport@ --- *
static int encrypt(int argc, char *argv[])
{
- const char *of = 0, *kn = "ccrypt";
+ const char *of = 0, *kn = "ccrypt", *skn = 0;
FILE *ofp = 0;
FILE *fp = 0;
const char *ef = "binary";
const char *err;
int i;
+ int en;
size_t n;
dstr d = DSTR_INIT;
octet *tag, *ct;
unsigned f = 0;
key_file kf;
key *k;
+ key *sk = 0;
kem *km;
+ sig *s = 0;
gcipher *cx, *c;
gmac *m;
ghash *h;
for (;;) {
static const struct option opt[] = {
{ "key", OPTF_ARGREQ, 0, 'k' },
+ { "sign-key", OPTF_ARGREQ, 0, 's' },
{ "armour", 0, 0, 'a' },
{ "armor", 0, 0, 'a' },
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "output", OPTF_ARGREQ, 0, 'o' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "k:af:o:", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "k:s:af:o:", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'k': kn = optarg; break;
+ case 's': skn = optarg; break;
case 'a': ef = "pem"; break;
case 'f': ef = optarg; break;
case 'o': of = optarg; break;
}
}
if (argc - optind > 1 || (f & f_bogus))
- die(EXIT_FAILURE, "Usage: encrypt [-options] [file]");
+ die(EXIT_FAILURE, "Usage: encrypt [-OPTIONS] [FILE]");
if (key_open(&kf, keyring, KOPEN_READ, keyreport, 0))
die(EXIT_FAILURE, "can't open keyring `%s'", keyring);
if ((k = key_bytag(&kf, kn)) == 0)
die(EXIT_FAILURE, "key `%s' not found", kn);
+ if (skn && (sk = key_bytag(&kf, skn)) == 0)
+ die(EXIT_FAILURE, "key `%s' not found", skn);
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
ofp, strerror(errno));
}
+ dstr_reset(&d);
key_fulltag(k, &d);
e = initenc(eo, ofp, "CATCRYPT ENCRYPTED MESSAGE", 1);
- km = getkem(k, "ccrypt", 0);
+ km = getkem(k, "cckem", 0);
if ((err = km->ops->check(km)) != 0)
moan("key `%s' fails check: %s", d.buf, err);
+ if (sk) {
+ dstr_reset(&d);
+ key_fulltag(sk, &d);
+ s = getsig(sk, "ccsig", 1);
+ if ((err = s->ops->check(s)) != 0)
+ moan("key `%s' fails check: %s", d.buf, err);
+ }
/* --- Build the header chunk --- */
dstr_ensure(&d, 256);
buf_init(&b, d.buf, 256);
buf_putu32(&b, k->id);
+ if (sk) buf_putu32(&b, sk->id);
assert(BOK(&b));
chunk_write(e, &b);
BSTEP(&b, d.len);
chunk_write(e, &b);
+ /* --- Write the signature chunk --- */
+
+ if (s) {
+ GC_ENCRYPT(cx, 0, bb, 1024);
+ GH_HASH(s->h, bb, 1024);
+ dstr_reset(&d);
+ if ((en = s->ops->doit(s, &d)) != 0)
+ die(EXIT_FAILURE, "error creating signature: %s", key_strerror(en));
+ buf_init(&b, d.buf, d.len);
+ BSTEP(&b, d.len);
+ chunk_write(e, &b);
+ }
+
/* --- Now do the main crypto --- */
assert(GC_CLASS(c)->blksz <= sizeof(bb));
GC_DESTROY(c);
GC_DESTROY(cx);
freeenc(e);
+ if (s) freesig(s);
freekem(km);
if (of) fclose(ofp);
key_close(&kf);
size_t seq;
uint32 id;
key *k;
+ key *sk = 0;
kem *km;
+ sig *s = 0;
gcipher *cx;
gcipher *c;
ghash *h;
octet *tag;
unsigned f = 0;
const encops *eo;
+ const char *err;
+ int verb = 1;
enc *e;
#define f_bogus 1u
static const struct option opt[] = {
{ "armour", 0, 0, 'a' },
{ "armor", 0, 0, 'a' },
+ { "verbose", 0, 0, 'v' },
+ { "quiet", 0, 0, 'q' },
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "output", OPTF_ARGREQ, 0, 'o' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "af:o:", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "af:o:qv", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'a': ef = "pem"; break;
+ case 'v': verb++; break;
+ case 'q': if (verb) verb--; break;
case 'f': ef = optarg; break;
case 'o': of = optarg; break;
default: f |= f_bogus; break;
}
}
if (argc - optind > 1 || (f & f_bogus))
- die(EXIT_FAILURE, "Usage: decrypt [-options] [file]");
+ die(EXIT_FAILURE, "Usage: decrypt [-OPTIONS] [FILE]");
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
/* --- Read the header chunk --- */
chunk_read(e, &d, &b);
- if (buf_getu32(&b, &id))
- die(EXIT_FAILURE, "malformed header: missing keyid");
- if (BLEFT(&b))
- die(EXIT_FAILURE, "malformed header: junk at end");
+ if (buf_getu32(&b, &id)) {
+ if (verb) printf("FAIL malformed header: missing keyid\n");
+ exit(EXIT_FAILURE);
+ }
+ if ((k = key_byid(&kf, id)) == 0) {
+ if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
+ exit(EXIT_FAILURE);
+ }
+ if (BLEFT(&b)) {
+ if (buf_getu32(&b, &id)) {
+ if (verb) printf("FAIL malformed header: missing signature keyid\n");
+ exit(EXIT_FAILURE);
+ }
+ if ((sk = key_byid(&kf, id)) == 0) {
+ if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (BLEFT(&b)) {
+ if (verb) printf("FAIL malformed header: junk at end\n");
+ exit(EXIT_FAILURE);
+ }
/* --- Find the key --- */
- if ((k = key_byid(&kf, id)) == 0)
- die(EXIT_FAILURE, "key id %08lx not found", (unsigned long)id);
- km = getkem(k, "ccrypt", 1);
+ km = getkem(k, "cckem", 1);
/* --- Read the KEM chunk --- */
chunk_read(e, &d, &b);
- if (setupkem(km, &d, &cx, &c, &m))
- die(EXIT_FAILURE, "failed to decapsulate key");
+ if (setupkem(km, &d, &cx, &c, &m)) {
+ if (verb) printf("FAIL failed to decapsulate key\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* --- Verify the signature, if there is one --- */
+
+ if (sk) {
+ s = getsig(sk, "ccsig", 0);
+ dstr_reset(&d);
+ key_fulltag(sk, &d);
+ if (verb && (err = s->ops->check(s)) != 0)
+ printf("WARN verification key %s fails check: %s\n", d.buf, err);
+ dstr_reset(&d);
+ dstr_ensure(&d, 1024);
+ GC_ENCRYPT(cx, 0, d.buf, 1024);
+ GH_HASH(s->h, d.buf, 1024);
+ chunk_read(e, &d, &b);
+ if (s->ops->doit(s, &d)) {
+ if (verb) printf("FAIL signature verification failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (verb) {
+ dstr_reset(&d);
+ key_fulltag(sk, &d);
+ printf("INFO good signature from %s\n", d.buf);
+ }
+ } else if (verb)
+ printf("INFO no signature packet\n");
/* --- Now decrypt the main body --- */
- if (!of || strcmp(of, "-") == 0)
+ if (!of || strcmp(of, "-") == 0) {
ofp = stdout;
- else if ((ofp = fopen(of, "wb")) == 0) {
+ if (verb) printf("DATA\n");
+ } else if ((ofp = fopen(of, "wb")) == 0) {
die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
ofp, strerror(errno));
}
GH_HASH(h, d.buf, 4);
seq++;
chunk_read(e, &d, &b);
- if ((tag = buf_get(&b, GM_CLASS(m)->hashsz)) == 0)
- die(EXIT_FAILURE, "bad ciphertext chunk: no tag");
+ if ((tag = buf_get(&b, GM_CLASS(m)->hashsz)) == 0) {
+ if (verb) printf("%sFAIL bad ciphertext chunk: no tag\n",
+ ofp == stdout ? "\n" : "");
+ exit(EXIT_FAILURE);
+ }
GH_HASH(h, BCUR(&b), BLEFT(&b));
- if (memcmp(tag, GH_DONE(h, 0), GM_CLASS(m)->hashsz) != 0)
- die(EXIT_FAILURE, "bad ciphertext chunk: authentication failure");
+ if (memcmp(tag, GH_DONE(h, 0), GM_CLASS(m)->hashsz) != 0) {
+ if (verb)
+ printf("%sFAIL bad ciphertext chunk: authentication failure\n",
+ ofp == stdout ? "\n" : "");
+ exit(EXIT_FAILURE);
+ }
if (!BLEFT(&b))
break;
GC_DECRYPT(c, BCUR(&b), BCUR(&b), BLEFT(&b));
- if (fwrite(BCUR(&b), 1, BLEFT(&b), ofp) != BLEFT(&b))
- die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+ if (fwrite(BCUR(&b), 1, BLEFT(&b), ofp) != BLEFT(&b)) {
+ if (verb) printf("%sFAIL error writing output: %s\n",
+ ofp == stdout ? "\n" : "", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (fflush(ofp) || ferror(ofp)) {
+ if (verb) printf("%sFAIL error writing output: %s\n",
+ ofp == stdout ? "\n" : "", strerror(errno));
+ exit(EXIT_FAILURE);
}
- if (fflush(ofp) || ferror(ofp))
- die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
-
e->ops->decdone(e);
+ if (verb && ofp != stdout)
+ printf("OK decrypted successfully\n");
freeenc(e);
GC_DESTROY(c);
GC_DESTROY(cx);
}
}
if (argc - optind > 1 || (f & f_bogus))
- die(EXIT_FAILURE, "Usage: encode [-options] [file]");
+ die(EXIT_FAILURE, "Usage: encode [-OPTIONS] [FILE]");
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
}
}
if (argc - optind > 1 || (f & f_bogus))
- die(EXIT_FAILURE, "Usage: decode [-options] [file]");
+ die(EXIT_FAILURE, "Usage: decode [-OPTIONS] [FILE]");
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
/*----- Main code ---------------------------------------------------------*/
-typedef struct cmd {
- const char *name;
- int (*func)(int /*argc*/, char */*argv*/[]);
- const char *usage;
- const char *help;
-} cmd;
+#define LISTS(LI) \
+ LI("Lists", list, \
+ listtab[i].name, listtab[i].name) \
+ LI("Key-encapsulation mechanisms", kem, \
+ kemtab[i].name, kemtab[i].name) \
+ LI("Signature schemes", sig, \
+ sigtab[i].name, sigtab[i].name) \
+ LI("Encodings", enc, \
+ enctab[i].name, enctab[i].name) \
+ LI("Symmetric encryption algorithms", cipher, \
+ gciphertab[i], gciphertab[i]->name) \
+ LI("Hash functions", hash, \
+ ghashtab[i], ghashtab[i]->name) \
+ LI("Message authentication codes", mac, \
+ gmactab[i], gmactab[i]->name)
+
+MAKELISTTAB(listtab, LISTS)
+
+int cmd_show(int argc, char *argv[])
+{
+ return (displaylists(listtab, argv + 1));
+}
+
+static int cmd_help(int, char **);
static cmd cmdtab[] = {
+ { "help", cmd_help, "help [COMMAND...]" },
+ { "show", cmd_show, "show [ITEM...]" },
{ "encode", encode,
- "encode [-f format] [-b label] [-o output] [file]",
+ "encode [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]",
"\
Options:\n\
\n\
-o, --output=FILE Write output to FILE.\n\
" },
{ "decode", decode,
- "decode [-f format] [-b label] [-o output] [file]",
+ "decode [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]",
"\
Options:\n\
\n\
-o, --output=FILE Write output to FILE.\n\
" },
{ "encrypt", encrypt,
- "encrypt [-a] [-k tag] [f format]] [-o output] [file]",
- "\
+ "encrypt [-a] [-k TAG] [-s TAG] [-f FORMAT]\n\t\
+[-o OUTPUT] [FILE]", "\
Options:\n\
\n\
-a, --armour Same as `-f pem'.\n\
-f, --format=FORMAT Encode as FORMAT.\n\
--k, --key=TAG Use public key named by TAG.\n\
+-k, --key=TAG Use public encryption key named by TAG.\n\
+-s, --sign-key=TAG Use private signature key named by TAG.\n\
-o, --output=FILE Write output to FILE.\n\
" },
{ "decrypt", decrypt,
- "decrypt [-t] [-o output] [file]", "\
+ "decrypt [-aqv] [-f FORMAT] [-o OUTPUT] [FILE]", "\
Options:\n\
\n\
--t, --text Read PEM-encoded input.\n\
+-a, --armour Same as `-f pem'.\n\
+-v, --verbose Produce more verbose messages.\n\
+-q, --quiet Produce fewer messages.\n\
+-f, --format=FORMAT Decode as FORMAT.\n\
-o, --output=FILE Write output to FILE.\n\
" },
{ 0, 0, 0 }
};
-/* --- @findcmd@ --- *
- *
- * Arguments: @const char *name@ = a command name
- *
- * Returns: Pointer to the command structure.
- *
- * Use: Looks up a command by name. If the command isn't found, an
- * error is reported and the program is terminated.
- */
-
-static cmd *findcmd(const char *name)
+static int cmd_help(int argc, char **argv)
{
- cmd *c, *chosen = 0;
- size_t sz = strlen(name);
-
- for (c = cmdtab; c->name; c++) {
- if (strncmp(name, c->name, sz) == 0) {
- if (c->name[sz] == 0) {
- chosen = c;
- break;
- } else if (chosen)
- die(EXIT_FAILURE, "ambiguous command name `%s'", name);
- else
- chosen = c;
- }
- }
- if (!chosen)
- die(EXIT_FAILURE, "unknown command name `%s'", name);
- return (chosen);
+ sc_help(cmdtab, stdout, argv + 1);
+ return (0);
}
-static void version(FILE *fp)
+void version(FILE *fp)
{
pquis(fp, "$, Catacomb version " VERSION "\n");
}
static void usage(FILE *fp)
{
- pquis(fp, "Usage: $ [-k keyring] command [args]\n");
+ pquis(fp, "Usage: $ [-k KEYRING] COMMAND [ARGS]\n");
}
-static void help(FILE *fp, char **argv)
+void help_global(FILE *fp)
{
- cmd *c;
-
- if (*argv) {
- c = findcmd(*argv);
- fprintf(fp, "Usage: %s [-k keyring] %s\n", QUIS, c->usage);
- if (c->help) {
- fputc('\n', fp);
- fputs(c->help, fp);
- }
- } else {
- version(fp);
- fputc('\n', fp);
- usage(fp);
- fputs("\n\
+ usage(fp);
+ fputs("\n\
Encrypt and decrypt files.\n\
-\n", fp);
- for (c = cmdtab; c->name; c++)
- fprintf(fp, "%s\n", c->usage);
- }
+\n\
+Global command-line options:\n\
+\n\
+-h, --help [COMMAND...] Show this help message, or help for COMMANDs.\n\
+-v, --version Show program version number.\n\
+-u, --usage Show a terse usage message.\n\
+\n\
+-k, --keyring=FILE Read keys from FILE.\n",
+ fp);
}
/* --- @main@ --- *
*
* Returns: Zero if successful, nonzero otherwise.
*
- * Use: Signs or verifies signatures on lists of files. Useful for
- * ensuring that a distribution is unmolested.
+ * Use: Encrypts or decrypts files.
*/
int main(int argc, char *argv[])
break;
switch (i) {
case 'h':
- help(stdout, argv + optind);
+ sc_help(cmdtab, stdout, argv + optind);
exit(0);
break;
case 'v':
/* --- Dispatch to the correct subcommand handler --- */
- return (findcmd(argv[0])->func(argc, argv));
+ return (findcmd(cmdtab, argv[0])->cmd(argc, argv));
#undef f_bogus
}
/* -*-c-*-
*
- * $Id: cc-enc.c,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ * $Id$
*
* Catcrypt data encoding
*
/* --- Encoder table --- */
-static const encops enctab[] = {
+const encops enctab[] = {
{ "binary", "rb", "wb",
bin_init, bin_init,
bin_read, bin_write,
/* -*-c-*-
*
- * $Id: cc-kem.c,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ * $Id$
*
* Catcrypt key-encapsulation
*
/* --- The switch table --- */
-static const struct kemtab {
- const char *name;
- const kemops *encops;
- const kemops *decops;
-} kemtab[] = {
+const struct kemtab kemtab[] = {
{ "rsa", &rsa_encops, &rsa_decops },
{ "dh", &dh_encops, &dh_decops },
{ "ec", &ec_encops, &ec_decops },
octet *kd;
size_t n, cn, mn;
ghash *h;
- int rc = 0;
+ int rc = -1;
h = GH_INIT(k->h);
if (k->ops->doit(k, d, h))
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Emit lists of things in tables
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/report.h>
+
+#include "cc.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @displaylists@ --- *
+ *
+ * Arguments: @const struct listent *listtab@ = table of lists to show
+ * @char *const argv[]@ = list of lists to show
+ *
+ * Returns: Nonzero if anything failed.
+ *
+ * Use: Dumps the named lists, or all of them.
+ */
+
+int displaylists(const struct listent *listtab, char *const argv[])
+{
+ const struct listent *li;
+ int i;
+ int rc = 0;
+
+ if (!argv || !*argv) {
+ for (li = listtab; li->name; li++)
+ li->list();
+ } else {
+ for (i = 0; argv[i]; i++) {
+ for (li = listtab; li->name; li++) {
+ if (strcmp(li->name, argv[i]) == 0) {
+ li->list();
+ goto cool;
+ }
+ }
+ moan("unknown list `%s'", argv[i]);
+ rc = 1;
+ cool:;
+ }
+ }
+ return (rc);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
/* -*-c-*-
*
- * $Id: cc-sig.c,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ * $Id$
*
* Catcrypt signatures
*
/* --- The switch table --- */
-static const struct sigtab {
- const char *name;
- const sigops *signops;
- const sigops *verifyops;
- const gchash *ch;
-} sigtab[] = {
+const struct sigtab sigtab[] = {
{ "rsapkcs1", &rsap1_sig, &rsap1_vrf, &sha },
{ "rsapss", &rsapss_sig, &rsapss_vrf, &sha },
{ "dsa", &dsa_sig, &dsa_vrf, &sha },
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Subcommand infrastructure
+ *
+ * (c) 2004 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+#include "cc.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @findcmd@ --- *
+ *
+ * Arguments: @const cmd *cmds@ = pointer to command table
+ * @const char *name@ = a command name
+ *
+ * Returns: Pointer to the command structure.
+ *
+ * Use: Looks up a command by name. If the command isn't found, an
+ * error is reported and the program is terminated.
+ */
+
+const cmd *findcmd(const cmd *cmds, const char *name)
+{
+ const cmd *c, *chosen = 0;
+ size_t sz = strlen(name);
+
+ for (c = cmds; c->name; c++) {
+ if (strncmp(name, c->name, sz) == 0) {
+ if (c->name[sz] == 0) {
+ chosen = c;
+ break;
+ } else if (chosen)
+ die(EXIT_FAILURE, "ambiguous command name `%s'", name);
+ else
+ chosen = c;
+ }
+ }
+ if (!chosen)
+ die(EXIT_FAILURE, "unknown command name `%s'", name);
+ return (chosen);
+}
+
+/* --- @sc_help@ --- *
+ *
+ * Arguments: @const cmd *cmds@ = pointer to command table
+ * @FILE *fp@ = output file handle
+ * @char *const *argv@ = remaining arguments
+ *
+ * Returns: ---
+ *
+ * Use: Prints a help message, maybe with help about subcommands.
+ */
+
+void sc_help(const cmd *cmds, FILE *fp, char *const *argv)
+{
+ const cmd *c;
+
+ version(fp);
+ fputc('\n', fp);
+ if (!*argv) {
+ help_global(fp);
+ fputs("\n\
+The following commands are understood:\n\n",
+ fp);
+ for (c = cmds; c->name; c++)
+ fprintf(fp, "%s\n", c->usage);
+ } else {
+ while (*argv) {
+ c = findcmd(cmds, *argv);
+ fprintf(fp, "Usage: %s [-OPTIONS] %s\n", QUIS, c->usage);
+ if (c->help) {
+ fputc('\n', fp);
+ pquis(fp, c->help);
+ }
+ argv++;
+ if (*argv) fputc('\n', fp);
+ }
+ }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
/* -*-c-*-
*
- * $Id: cc.h,v 1.1 2004/04/17 09:58:37 mdw Exp $
+ * $Id$
*
* Catcrypt common stuff
*
/*----- Header files ------------------------------------------------------*/
#include <stdio.h>
+#include <string.h>
#include <mLib/dstr.h>
void (*destroy)(kem */*k*/);
} kemops;
+struct kemtab {
+ const char *name;
+ const kemops *encops;
+ const kemops *decops;
+};
+
+extern const struct kemtab kemtab[];
+
/* --- Signing --- */
typedef struct sig {
void (*destroy)(sig */*s*/);
} sigops;
+struct sigtab {
+ const char *name;
+ const sigops *signops;
+ const sigops *verifyops;
+ const gchash *ch;
+};
+
+extern const struct sigtab sigtab[];
+
/* --- Data encoding --- */
typedef struct enc {
void (*destroy)(enc */*e*/);
} encops;
+extern const encops enctab[];
+
/*----- Functions provided ------------------------------------------------*/
/* --- @getkem@ --- *
extern void freeenc(enc */*e*/);
+/* --- @LIST(STRING, FP, END-TEST, NAME-EXPR)@ --- *
+ *
+ * Produce list of things. Requires @i@ and @w@ variables in scope.
+ * END-TEST and NAME-EXPR are in terms of @i@.
+ */
+
+#define LIST(what, fp, end, name) do { \
+ fputs(what ":\n ", fp); \
+ w = 2; \
+ for (i = 0; end; i++) { \
+ if (w == 2) \
+ w += strlen(name); \
+ else { \
+ if (strlen(name) + w > 76) { \
+ fputs("\n ", fp); \
+ w = 2 + strlen(name); \
+ } else { \
+ fputc(' ', fp); \
+ w += strlen(name) + 1; \
+ } \
+ } \
+ fputs(name, fp); \
+ } \
+ fputc('\n', fp); \
+} while (0)
+
+#define STDLISTS(LI) \
+ LI("Hash functions", hash, \
+ ghashtab[i], ghashtab[i]->name) \
+ LI("Encryption schemes", enc, \
+ gciphertab[i], gciphertab[i]->name) \
+ LI("Message authentication schemes", mac, \
+ gmactab[i], gmactab[i]->name) \
+ LI("Elliptic curves", ec, \
+ ectab[i].name, ectab[i].name) \
+ LI("Diffie-Hellman groups", dh, \
+ ptab[i].name, ptab[i].name)
+
+#define LIDECL(text, tag, test, name) \
+ static void show_##tag(void);
+
+#define LIDEF(text, tag, test, name) \
+ static void show_##tag(void) \
+ { \
+ unsigned i, w; \
+ LIST(text, stdout, test, name); \
+ }
+
+#define LIENT(text, tag, test, name) \
+ { #tag, show_##tag },
+
+struct listent {
+ const char *name;
+ void (*list)(void);
+};
+
+#define MAKELISTTAB(listtab, LISTS) \
+ LISTS(LIDECL) \
+ static const struct listent listtab[] = { \
+ LISTS(LIENT) \
+ { 0, 0 } \
+ }; \
+ LISTS(LIDEF)
+
+extern int displaylists(const struct listent */*listtab*/,
+ char *const /*argv*/[]);
+
+/*----- Subcommand dispatch -----------------------------------------------*/
+
+typedef struct cmd {
+ const char *name;
+ int (*cmd)(int /*argc*/, char */*argv*/[]);
+ const char *usage;
+ const char *help;
+} cmd;
+
+extern void version(FILE */*fp*/);
+extern void help_global(FILE */*fp*/);
+
+/* --- @findcmd@ --- *
+ *
+ * Arguments: @const cmd *cmds@ = pointer to command table
+ * @const char *name@ = a command name
+ *
+ * Returns: Pointer to the command structure.
+ *
+ * Use: Looks up a command by name. If the command isn't found, an
+ * error is reported and the program is terminated.
+ */
+
+const cmd *findcmd(const cmd */*cmds*/, const char */*name*/);
+
+/* --- @sc_help@ --- *
+ *
+ * Arguments: @const cmd *cmds@ = pointer to command table
+ * @FILE *fp@ = output file handle
+ * @char *const *argv@ = remaining arguments
+ *
+ * Returns: ---
+ *
+ * Use: Prints a help message, maybe with help about subcommands.
+ */
+
+extern void sc_help(const cmd */*cmds*/, FILE */*fp*/,
+ char *const */*argv*/);
+
/*----- That's all, folks -------------------------------------------------*/
#ifdef __cplusplus
--- /dev/null
+.\" -*-nroff-*-
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t \{\
+. if \n(.g \{\
+. fam P
+. \}
+.\}
+.ie t .ds o \(bu
+.el .ds o o
+.
+.TH cookie 1 "5 June 1999" "Straylight/Edgeware" "Catacomb cryptographic library"
+.SH NAME
+cookie \- generate and validate cryptographic cookies
+.SH SYNOPSIS
+.B cookie
+.RB [ \-k
+.IR keyring ]
+.I command
+.PP
+where command is one of:
+.PP
+.B help
+.RI [ command ...]
+.br
+.B show
+.RI [ item ...]
+.br
+.B generate
+.RB [ \-b
+.IR bits ]
+.RB [ \-e
+.IR expire ]
+.RB [ \-k
+.IR tag ]
+.I data
+.br
+.B verify
+.RB [ \-fquv ]
+.RB [ \-b
+.IR bits ]
+.RB [ \-m
+.IR bits ]
+.I cookie
+.RI [ data ]
+.SH DESCRIPTION
+The
+.B cookie
+program generates timestamped cryptographic cookies which can be handed
+out to clients and later validated. It provides two subcommands: one to
+create a new cookie, and one to ensure that a particular cookie is
+valid.
+.SS "Global options"
+Before the command name,
+.I "global options"
+may be given. The following global options are supported:
+.TP
+.BR "\-h, \-\-help " [ \fIcommand ...]
+Displays help text for
+.B cookie
+on standard output and exits successfullly. With command names, gives
+help on each command.
+.TP
+.B "\-v, \-\-version"
+Displays
+.BR cookie 's
+version number on standard output and exits successfullly.
+.TP
+.B "\-u, \-\-usage"
+Displays an unhelpfully terse usage summary on standard output and exits
+successfully.
+.TP
+.BI "\-k, \-\-keyring " file
+Use
+.I file
+as the keyring file rather than the default, which is the file named
+.B keyring
+in the current directory. See
+.BR key (1)
+and
+.BR keyring (5)
+for more details about keyring files.
+.SH "KEY SETUP"
+The message authentication algorithm used to tag and verify cookies is
+described by an attribute on the key, or its type. If the key has a
+.B mac
+attribute, then that is taken to be the name of the MAC algorithm to
+use; otherwise the key must have the type
+.BR cookie- \c
+.IR mac .
+.SH "COMMAND REFERENCE"
+.SS help
+The
+.B help
+command behaves exactly as the
+.B \-\-help
+option. With no arguments, it shows an overview of
+.BR cookie 's
+options; with arguments, it describes the named subcommands.
+.SS show
+The
+.B show
+command prints various lists of tokens understood by
+.BR cookie .
+With no arguments, it prints all of the lists; with arguments, it prints
+just the named lists, in order. The recognized lists can be enumerated
+using the
+.VS
+cookie show list
+.VE
+command. The lists are as follows.
+.TP
+.B list
+The lists which can be enumerated by the
+.B show
+command.
+.TP
+.B mac
+The message authentication algorithms which can be used in a key's
+.B mac
+attribute.
+.SS generate
+The
+.B generate
+command creates a new cookie. The command understands the following
+options:
+.TP
+.BI "\-b, \-\-bits " bits
+Specifies the size of the cryptographic token to generate. The default
+token size is 32 bits.
+.TP
+.BI "\-e, \-\-expire " expire
+The expiry date for the cookie. This may be the string
+.RB ` forever '
+if the cookie should never expire, or any date acceptable to the
+.BR getdate (3)
+library function, e.g.,
+.RB ` "+2 weeks" '.
+It is an error to ask for a non-expiring cookie to be created using a
+key which will expire.
+.TP
+.BI "\-k, \-\-key " tag
+Use the key named
+.I tag
+to authenticate the cookie; the default key is named
+.BR cookie .
+.PP
+If a
+.I data
+argument is supplied, then an identical argument must be supplied to the
+.B verify
+command if the cookie is to be accepted as valid. The data will usually
+be some way of identifying the cookie's recipient, e.g., an email
+address.
+.PP
+The generated cookie is written to standard output, followed by a
+newline. Cookies are not architecture-specific.
+.SS verify
+The
+.B verify
+command checks a cookie for validity. It accepts the following
+options:
+.TP
+.BI "\-b, \-\-bits " bits
+Only accept a cookie with a cryptographic token exactly
+.I bits
+bits long.
+.TP
+.BI "\-m, \-\-min\-bits " bits
+Only accept a cookie with a cryptographic token at least
+.I bits
+bits long. The default is to accept any token with size 32 bits or
+more.
+.TP
+.B "\-f, \-\-forever"
+Allow non-expiring cookies. Without this option, cookies which never
+expire are automatically rejected by
+.BR cookie .
+.TP
+.B "\-u, \-\-utc"
+Display expiry time as UTC rather than using the local time zone.
+.TP
+.B "\-q, \-\-quiet"
+Make
+.B cookie
+more quiet. Repeat for a greater effect.
+.TP
+.B "\-v, \-\-verbose"
+Make
+.B cookie
+more verbose. Repeat for a greater effect.
+.PP
+The argument
+.I cookie
+is the cookie to check. The cookie may have whitespace before, after
+or within it.
+.PP
+If
+.I data
+is specified, it must exactly match the data passed to
+.B generate
+if the cookie is to be accepted.
+.PP
+Each line of text emitted by the
+.B verify
+command begins with a status indicator, which is one of the following:
+.TP
+.B INFO
+This line provides possibly useful information about the cookie.
+.B INFO
+lines are displayed while
+.B cookie
+is working, before it's made its mind up about whether to reject the
+cookie. The remainder of the line contains the information gleaned.
+.TP
+.B FAIL
+The cookie is invalid. The remainder of the line is a human-readable
+error message giving a reason for rejecting the cookie.
+.TP
+.B OK
+The cookie is valid.
+.PP
+The
+.B \-q
+and
+.B \-v
+flags control the amount of output that
+.B cookie
+generates. By default, only
+.B OK
+and
+.B FAIL
+lines are generated. One
+.B \-v
+option shows the cookie's keyid and expiry time. Two
+.B \-v
+options also show the authentication token width. A
+.B \-q
+option suppresses all output, or cancels out a previous
+.BR \-v .
+.PP
+Regardless of how much output is generated,
+.B cookie
+exits with return code 0 if the cookie was accepted and return code 1 if
+validation failed for some reason.
+.SH "COOKIE FORMAT"
+Cookies are Base64-encoded binary objects. The binary data consists of:
+.hP \*o
+A 32-bit keyid referring to the key with which the cookie was created.
+.hP \*o
+An expiry date, expressed as a 64-bit integer in the format returned by
+the
+.BR time (2)
+system call.
+.hP \*o
+The `authentication token', which is the leftmost bits of a MAC over the
+keyid and date and any extra data supplied to the
+.B generate
+command
+.PP
+The keyid and expiry date are stored in network (big-endian) byte order.
+.SH "SEE ALSO"
+.BR key (1).
+.SH "AUTHOR"
+Mark Wooding, <mdw@nsict.org>
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Generate and validate cryptographic cookies
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Catacomb; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <mLib/base64.h>
+#include <mLib/bits.h>
+#include <mLib/dstr.h>
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+#include <mLib/sub.h>
+
+#include "cc.h"
+#include "key.h"
+#include "gmac.h"
+#include "getdate.h"
+
+/*----- Handy global state ------------------------------------------------*/
+
+static const char *keyfile = "keyring";
+
+/*----- Cookie format -----------------------------------------------------*/
+
+/* --- Cookie header structure (unpacked) --- */
+
+typedef struct cookie {
+ uint32 k;
+ time_t exp;
+} cookie;
+
+/* --- Size of a cookie header (packed) --- */
+
+#define COOKIE_SZ (4 + 8)
+
+/* --- @COOKIE_PACK@ --- *
+ *
+ * Arguments: @p@ = pointer to destination buffer
+ * @c@ = pointer to source cookie header block
+ *
+ * Use: Packs a cookie header into an octet buffer in a machine-
+ * independent way.
+ */
+
+#define COOKIE_PACK(p, c) do { \
+ octet *_p = (octet *)(p); \
+ const cookie *_c = (c); \
+ STORE32(_p + 0, _c->k); \
+ STORE32(_p + 4, ((_c->exp & ~MASK32) >> 16) >> 16); \
+ STORE32(_p + 8, _c->exp); \
+} while (0)
+
+/* --- @COOKIE_UNPACK@ --- *
+ *
+ * Arguments: @c@ = pointer to destination cookie header
+ * @p@ = pointer to source buffer
+ *
+ * Use: Unpacks a cookie header from an octet buffer into a
+ * machine-specific but comprehensible structure.
+ */
+
+#define COOKIE_UNPACK(c, p) do { \
+ cookie *_c = (c); \
+ const octet *_p = (const octet *)(p); \
+ _c->k = LOAD32(_p + 0); \
+ _c->exp = ((time_t)(((LOAD32(_p + 4) << 16) << 16) & ~MASK32) | \
+ (time_t)LOAD32(_p + 8)); \
+} while (0)
+
+/*----- Useful shared functions -------------------------------------------*/
+
+/* --- @doopen@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ * @unsigned how@ = method to open file with
+ *
+ * Returns: ---
+ *
+ * Use: Opens a key file and handles errors by panicking
+ * appropriately.
+ */
+
+static void doopen(key_file *f, unsigned how)
+{
+ if (key_open(f, keyfile, how, key_moan, 0)) {
+ die(EXIT_FAILURE, "couldn't open file `%s': %s",
+ keyfile, strerror(errno));
+ }
+}
+
+/* --- @doclose@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ *
+ * Returns: ---
+ *
+ * Use: Closes a key file and handles errors by panicking
+ * appropriately.
+ */
+
+static void doclose(key_file *f)
+{
+ switch (key_close(f)) {
+ case KWRITE_FAIL:
+ die(EXIT_FAILURE, "couldn't write file `%s': %s",
+ keyfile, strerror(errno));
+ case KWRITE_BROKEN:
+ die(EXIT_FAILURE, "keyring file `%s' broken: %s (repair manually)",
+ keyfile, strerror(errno));
+ }
+}
+
+/* --- @getmac@ --- *
+ *
+ * Arguments: @key *k@ = key to use
+ * @const char *app@ = application name
+ *
+ * Returns: The MAC to use.
+ *
+ * Use: Finds the right MAC for the given key.
+ */
+
+static gmac *getmac(key *k, const char *app)
+{
+ dstr t = DSTR_INIT;
+ dstr d = DSTR_INIT;
+ char *p = 0;
+ const char *q;
+ size_t n;
+ key_bin kb;
+ key_packdef kp;
+ const gcmac *cm;
+ int e;
+ gmac *m;
+
+ /* --- Set up --- */
+
+ key_fulltag(k, &t);
+
+ /* --- Pick out the right MAC --- */
+
+ n = strlen(app);
+ if ((q = key_getattr(0, k, "mac")) != 0) {
+ dstr_puts(&d, q);
+ p = d.buf;
+ } else if (strncmp(k->type, app, n) == 0 && k->type[n] == '-') {
+ dstr_puts(&d, k->type);
+ p = d.buf + n + 1;
+ } else
+ die(EXIT_FAILURE, "no MAC algorithm for key `%s'", t.buf);
+ if ((cm = gmac_byname(p)) == 0) {
+ die(EXIT_FAILURE, "MAC algorithm `%s' not found in key `%s'",
+ p, t.buf);
+ }
+
+ /* --- Unlock the key --- */
+
+ kp.kd.e = KENC_BINARY;
+ kp.p = &kb;
+ if ((e = key_unpack(&kp, &k->k, &t)) != 0) {
+ die(EXIT_FAILURE, "error unpacking key `%s': %s",
+ t.buf, key_strerror(e));
+ }
+
+ /* --- Make the MAC object --- */
+
+ if (keysz(kb.sz, cm->keysz) != kb.sz)
+ die(EXIT_FAILURE, "key %s has bad length (%lu) for MAC %s",
+ t.buf, (unsigned long)kb.sz, cm->name);
+ m = cm->key(kb.k, kb.sz);
+ key_unpackdone(&kp);
+ return (m);
+}
+
+/*----- Command implementation --------------------------------------------*/
+
+/* --- @cmd_gen@ --- */
+
+static int cmd_gen(int argc, char *argv[])
+{
+ key_file f;
+ key *k;
+ gmac *m;
+ ghash *h;
+ const char *tag = "cookie";
+ int err;
+ cookie c = { 0, KEXP_EXPIRE };
+ unsigned fl = 0;
+ int bits = 32;
+ const octet *t;
+ dstr d = DSTR_INIT;
+ octet buf[COOKIE_SZ];
+ base64_ctx b;
+
+ /* --- Various useful flag bits --- */
+
+#define f_bogus 1u
+
+ /* --- Parse options for the subcommand --- */
+
+ for (;;) {
+ static struct option opt[] = {
+ { "bits", OPTF_ARGREQ, 0, 'b' },
+ { "expire", OPTF_ARGREQ, 0, 'e' },
+ { "key", OPTF_ARGREQ, 0, 'k' },
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "+b:e:i:t:", opt, 0, 0, 0);
+ if (i < 0)
+ break;
+
+ /* --- Handle the various options --- */
+
+ switch (i) {
+
+ /* --- Fetch a size in bits --- */
+
+ case 'b':
+ if (!(bits = atoi(optarg)) || bits % 8)
+ die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
+ break;
+
+ /* --- Fetch an expiry time --- */
+
+ case 'e':
+ if (strcmp(optarg, "forever") == 0)
+ c.exp = KEXP_FOREVER;
+ else if ((c.exp = get_date(optarg, 0)) == -1)
+ die(EXIT_FAILURE, "bad expiry date: `%s'", optarg);
+ break;
+
+ /* --- Fetch a key type --- */
+
+ case 'k':
+ tag = optarg;
+ break;
+
+ /* --- Other things are bogus --- */
+
+ default:
+ fl |= f_bogus;
+ break;
+ }
+ }
+
+ /* --- Various sorts of bogosity --- */
+
+ if (fl & f_bogus || optind + 1 < argc)
+ die(EXIT_FAILURE,
+ "Usage: generate [-b BITS] [-e TIME] [-k TAG] [DATA]");
+
+ /* --- Choose a default expiry time --- */
+
+ if (c.exp == KEXP_EXPIRE)
+ c.exp = time(0) + 7 * 24 * 60 * 60;
+
+ /* --- Open the key file and get the key --- */
+
+ doopen(&f, KOPEN_WRITE);
+ if ((k = key_bytag(&f, tag)) == 0) {
+ die(EXIT_FAILURE, "no key with tag `%s' in keyring `%s'",
+ tag, keyfile);
+ }
+
+ c.k = k->id;
+ if ((err = key_used(&f, k, c.exp)) != 0)
+ die(EXIT_FAILURE, "can't generate cookie: %s", key_strerror(err));
+ m = getmac(k, "cookie");
+ if (bits/8 > GM_CLASS(m)->hashsz) {
+ die(EXIT_FAILURE, "inapproriate bit length for `%s' MACs",
+ GM_CLASS(m)->name);
+ }
+
+ /* --- Store and MAC the cookie --- */
+
+ COOKIE_PACK(buf, &c);
+
+ h = GM_INIT(m);
+ GH_HASH(h, buf, sizeof(buf));
+ if (argv[optind])
+ GH_HASH(h, argv[optind], strlen(argv[optind]));
+ t = GH_DONE(h, 0);
+
+ /* --- Encode and emit the finished cookie --- */
+
+ base64_init(&b);
+ b.indent = "";
+ base64_encode(&b, buf, sizeof(buf), &d);
+ base64_encode(&b, t, bits/8, &d);
+ base64_encode(&b, 0, 0, &d);
+ DWRITE(&d, stdout);
+ fputc('\n', stdout);
+ DDESTROY(&d);
+ GH_DESTROY(h);
+ GM_DESTROY(m);
+
+ doclose(&f);
+ return (0);
+
+#undef f_bogus
+}
+
+/* --- @cmd_verify@ --- */
+
+static int cmd_verify(int argc, char *argv[])
+{
+ key_file f;
+ dstr d = DSTR_INIT;
+ unsigned fl = 0;
+ int bits = -1, minbits = 32;
+ int v = 1;
+ base64_ctx b;
+ gmac *m;
+ ghash *h;
+ cookie c;
+ key *k;
+ int cbits;
+ const octet *t;
+ time_t now = time(0);
+
+ /* --- Various useful flag bits --- */
+
+#define f_bogus 1u
+#define f_forever 2u
+#define f_utc 4u
+
+ /* --- Parse options for the subcommand --- */
+
+ for (;;) {
+ static struct option opt[] = {
+ { "bits", OPTF_ARGREQ, 0, 'b' },
+ { "min-bits", OPTF_ARGREQ, 0, 'm' },
+ { "forever", 0, 0, 'f' },
+ { "quiet", 0, 0, 'q' },
+ { "verbose", 0, 0, 'v' },
+ { "utc", 0, 0, 'u' },
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "+b:m:fqvu", opt, 0, 0, 0);
+ if (i < 0)
+ break;
+
+ /* --- Handle the various options --- */
+
+ switch (i) {
+
+ /* --- Fetch a size in bits --- */
+
+ case 'b':
+ if (!(bits = atoi(optarg)) || bits % 8)
+ die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
+ break;
+ case 'm':
+ if (!(minbits = atoi(optarg)) || minbits % 8)
+ die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
+ break;
+
+ /* --- Miscellaneous flags --- */
+
+ case 'f':
+ fl |= f_forever;
+ break;
+ case 'u':
+ fl |= f_utc;
+ break;
+ case 'q':
+ if (v > 0) v--;
+ break;
+ case 'v':
+ v++;
+ break;
+
+ /* --- Other things are bogus --- */
+
+ default:
+ fl |= f_bogus;
+ break;
+ }
+ }
+
+ /* --- Various sorts of bogosity --- */
+
+ if (fl & f_bogus || optind == argc || optind + 2 < argc) {
+ die(EXIT_FAILURE,
+ "Usage: verify [-fuqv] [-b BITS] [-m BITS] COOKIE [DATA]");
+ }
+ doopen(&f, KOPEN_READ);
+
+ /* --- Decode the base64 wrapping --- */
+
+ base64_init(&b);
+ base64_decode(&b, argv[optind], strlen(argv[optind]), &d);
+ base64_decode(&b, 0, 0, &d);
+
+ if (d.len < COOKIE_SZ + 1) {
+ if (v) printf("FAIL cookie too small\n");
+ goto fail;
+ }
+
+ /* --- Extract the relevant details --- */
+
+ COOKIE_UNPACK(&c, d.buf);
+
+ if (v > 1) {
+ char buf[64];
+ if (c.exp == KEXP_FOREVER)
+ strcpy(buf, "forever");
+ else {
+ struct tm *tm;
+ const char *fmt;
+
+ if (fl & f_utc) {
+ tm = gmtime(&c.exp);
+ fmt = "%Y-%m-%d %H:%M:%S UTC";
+ } else {
+ tm = localtime(&c.exp);
+ fmt = "%Y-%m-%d %H:%M:%S %Z";
+ }
+ strftime(buf, sizeof(buf), fmt, tm);
+ }
+ printf("INFO keyid = %08lx; expiry = %s\n", (unsigned long)c.k, buf);
+ }
+
+ /* --- Check the authentication token width --- */
+
+ cbits = (d.len - COOKIE_SZ) * 8;
+ if (v > 2) printf("INFO authentication token width = %i bits\n", cbits);
+ if (bits == -1) {
+ if (cbits < minbits) {
+ if (v) printf("FAIL authentication token too narrow\n");
+ goto fail;
+ }
+ } else {
+ if (cbits != bits) {
+ if (v) printf("FAIL authentication token width doesn't match\n");
+ goto fail;
+ }
+ }
+ /* --- Get the key --- */
+
+ if ((k = key_byid(&f, c.k)) == 0) {
+ if (v) printf("FAIL keyid %08lx unavailable\n", (unsigned long)c.k);
+ goto fail;
+ }
+
+ /* --- Check that the cookie authenticates OK --- */
+
+ m = getmac(k, "cookie");
+ h = GM_INIT(m);
+ GH_HASH(h, d.buf, COOKIE_SZ);
+ if (argv[optind + 1])
+ GH_HASH(h, argv[optind + 1], strlen(argv[optind + 1]));
+ t = GH_DONE(h, 0);
+
+ if (memcmp(t, d.buf + COOKIE_SZ, cbits / 8) != 0) {
+ if (v) printf("FAIL bad authentication token\n");
+ goto fail;
+ }
+
+ /* --- See whether the cookie has expired --- */
+
+ if (c.exp == KEXP_FOREVER) {
+ if (!(fl & f_forever)) {
+ if (v) printf("FAIL forever cookies not allowed\n");
+ goto fail;
+ }
+ if (k->exp != KEXP_FOREVER) {
+ if (v) printf("FAIL cookie lasts forever but key will expire\n");
+ goto fail;
+ }
+ } else if (c.exp < now) {
+ if (v) printf("FAIL cookie has expired\n");
+ goto fail;
+ }
+
+ if (v) printf("OK\n");
+ key_close(&f);
+ GM_DESTROY(m);
+ GH_DESTROY(h);
+ dstr_destroy(&d);
+ return (0);
+
+fail:
+ key_close(&f);
+ dstr_destroy(&d);
+ return (1);
+
+#undef f_bogus
+#undef f_forever
+#undef f_utc
+}
+
+/*----- Main command table ------------------------------------------------*/
+
+static int cmd_help(int, char **);
+
+#define LISTS(LI) \
+ LI("Lists", list, \
+ listtab[i].name, listtab[i].name) \
+ LI("Message authentication algorithms", mac, \
+ gmactab[i], gmactab[i]->name)
+
+MAKELISTTAB(listtab, LISTS)
+
+static int cmd_show(int argc, char *argv[])
+{
+ return (displaylists(listtab, argv + 1));
+}
+
+static cmd cmds[] = {
+ { "help", cmd_help, "help [COMMAND...]" },
+ { "show", cmd_show, "show [ITEM...]" },
+ { "generate", cmd_gen,
+ "generate [-b BITS] [-e TIME] [-k TAG] [DATA]", "\
+Options:\n\
+\n\
+-b, --bits=N Use an N-bit token in the cookie.\n\
+-e, --expire=TIME Make the cookie expire after TIME.\n\
+-k, --key=TAG Use key TAG to create the token.\n\
+" },
+ { "verify", cmd_verify,
+ "verify [-fuqv] [-b BITS] [-m BITS] COOKIE [DATA]", "\
+Options:\n\
+\n\
+-b, --bits=N Accept tokens exactly N bits long only.\n\
+-m, --min-bits=N Accept tokens N bits long or more.\n\
+-f, --forever Accept cookies which never expire.\n\
+-u, --utc Output cookie expiry dates in UTC.\n\
+-q, --quiet Produce less output while checking cookies.\n\
+-v, --verbose Produce more output while checking cookies.\n\
+" },
+ { 0, 0, 0 }
+};
+
+static int cmd_help(int argc, char *argv[])
+{
+ sc_help(cmds, stdout, argv + 1);
+ return (0);
+}
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- Helpful GNUy functions --- */
+
+static void usage(FILE *fp)
+{
+ fprintf(fp, "Usage: %s [-k KEYRING] COMMAND [ARGS]\n", QUIS);
+}
+
+void version(FILE *fp)
+{
+ fprintf(fp, "%s, Catacomb version " VERSION "\n", QUIS);
+}
+
+void help_global(FILE *fp)
+{
+ usage(fp);
+ fputs("\n\
+Generates and validates cryptographic cookies. Command line options\n\
+recognized are:\n\
+\n\
+-h, --help [COMMAND] Display this help text (or help for COMMAND).\n\
+-v, --version Display version number.\n\
+-u, --usage Display short usage summary.\n\
+\n\
+-k, --key-file=FILE Read and write keys in FILE.\n",
+ fp);
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments: @int argc@ = number of command line arguments
+ * @char *argv[]@ = array of arguments
+ *
+ * Returns: Zero if OK, nonzero if not.
+ *
+ * Use: Generates and validates cryptographic cookies.
+ */
+
+int main(int argc, char *argv[])
+{
+ unsigned f = 0;
+
+#define f_bogus 1u
+#define f_forever 2u
+
+ /* --- Initialize the library --- */
+
+ ego(argv[0]);
+ sub_init();
+
+ /* --- Options parsing --- */
+
+ for (;;) {
+ static struct option opt[] = {
+
+ /* --- Standard GNUy help options --- */
+
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'v' },
+ { "usage", 0, 0, 'u' },
+
+ /* --- Actual relevant options --- */
+
+ { "keyring", OPTF_ARGREQ, 0, 'k' },
+
+ /* --- Magic terminator --- */
+
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "+hvu k:", opt, 0, 0, 0);
+
+ if (i < 0)
+ break;
+ switch (i) {
+
+ /* --- Helpful GNUs --- */
+
+ case 'u':
+ usage(stdout);
+ exit(0);
+ case 'v':
+ version(stdout);
+ exit(0);
+ case 'h':
+ sc_help(cmds, stdout, argv + optind);
+ exit(0);
+
+ /* --- Real genuine useful options --- */
+
+ case 'k':
+ keyfile = optarg;
+ break;
+
+ /* --- Bogus things --- */
+
+ default:
+ f |= f_bogus;
+ break;
+ }
+ }
+
+ if ((f & f_bogus) || optind == argc) {
+ usage(stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ /* --- Dispatch to appropriate command handler --- */
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+ return (findcmd(cmds, argv[0])->cmd(argc, argv));
+
+#undef f_bogus
+#undef f_forever
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+.\" -*-nroff-*-
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
+.ie t \{\
+. if \n(.g \{\
+. fam P
+. \}
+.\}
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t .ds o \(bu
+.el .ds o o
+.TH dsig 1 "30 September 2004" "Straylight/Edgeware" "Catacomb cryptographic library"
+.SH NAME
+dsig \- compute and verify signatures on collections of files
+.SH SYNOPSIS
+.B dsig
+.RB [ \-k
+.IR keyring ]
+.I command
+.PP
+where
+.I command
+is one of:
+.PP
+.B help
+.RI [ command ...]
+.br
+.B show
+.RI [ item ...]
+.br
+.B sign
+.RB [ \-0bqv ]
+.RB [ \-c
+.IR comment ]
+.RB [ \-k
+.IR tag ]
+.RB [ \-e
+.IR expire ]
+.br
+\h'8n'
+.RB [ \-f
+.IR file ]
+.RB [ \-o
+.IR output ]
+.br
+.B verify
+.RB [ \-qv ]
+.RI [ file ]
+.SH DESCRIPTION
+The
+.B dsig
+command signs and verifies signatures on a collection of files. It
+provides a number of subcommands, by which the various operations may be
+carried out.
+.SS "Global options"
+Before the command name,
+.I "global options"
+may be given. The following global options are supported:
+.TP
+.BR "\-h, \-\-help " [ \fIcommand ...]
+Writes a brief summary of
+.BR dsig 's
+various options to standard output, and returns a successful exit
+status. With command names, gives help on those commands.
+.TP
+.B "\-v, \-\-version"
+Writes the program's version number to standard output, and returns a
+successful exit status.
+.TP
+.B "\-u, \-\-usage"
+Writes a very terse command line summary to standard output, and returns
+a successful exit status.
+.TP
+.BI "\-k, \-\-keyring " file
+Names the keyring file which
+.B key
+is to process. The default keyring, used if this option doesn't specify
+one, is the file named
+.B keyring
+in the current directory. See
+.BR key (1)
+and
+.BR keyring (5)
+for more details about keyring files.
+.SH "KEY SETUP"
+A
+.I sigalgspec
+has the form
+.IR sig \c
+.RB [ / \c
+.IR hash ].
+If a
+.B sig
+attribute is present on the key, then it must have this form; otherwise,
+the key's type must have the form
+.BI dsig- \c
+.IR sigalgspec .
+Algorithm selections are taken from appropriately-named attributes, or,
+failing that, from the
+.IR sigalgspec .
+.PP
+The signature algorithm is chosen according to the setting of
+.I sig
+as follows. Run
+.B dsig show sig
+for a list of supported signature algorithms.
+.TP
+.B rsapkcs1
+This is almost the same as the RSASSA-PKCS1-v1_5 algorithm described in
+RFC3447; the difference is that the hash is left bare rather than being
+wrapped in a DER-encoded
+.B DigestInfo
+structure. This doesn't affect security since the key can only be used
+with the one hash function anyway, and dropping the DER wrapping permits
+rapid adoption of new hash functions. Regardless, use of this algorithm
+is not recommended, since the padding method has been shown vulnerable
+to attack. Use the
+.B rsa
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B rsapss
+This is the RSASSA-PSS algorithm described in RFC3447. It is the
+preferred RSA-based signature scheme. Use the
+.B rsa
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B dsa
+This is the DSA algorithm described in FIPS180-1 and FIPS180-2. Use the
+.B dsa
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B ecdsa
+This is the ECDSA algorithm described in ANSI X9.62 and FIPS180-2. Use
+the
+.B ec
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.TP
+.B kcdsa
+This is the revised KCDSA (Korean Certificate-based Digital Signature
+Algorithm) described in
+.I The Revised Version of KCDSA
+.RB ( http://dasan.sejong.ac.kr/~chlim/pub/kcdsa1.ps ).
+Use the
+.B dh
+algorithm of the
+.B key add
+command with the
+.B \-LS
+options (see
+.BR key (1))
+to generate the key.
+.TP
+.B eckcdsa
+This is an unofficial elliptic-curve analogue of the KCDSA algorithm.
+Use the
+.B ec
+algorithm of the
+.B key add
+command (see
+.BR key (1))
+to generate the key.
+.PP
+As well as the signature algorithm itself, a hash function is used.
+This is taken from the
+.B hash
+attribute on the key, or, failing that, from the
+.I hash
+specified in the
+.IR sigalgspec ,
+or, if that is absent, determined by the signature algorithm as follows.
+.hP \*o
+For
+.BR rsapkcs1 ,
+.BR rsapss ,
+.BR dsa ,
+and
+.BR ecdsa ,
+the default hash function is
+.BR sha .
+.hP \*o
+For
+.BR kcdsa
+and
+.BR eckcdsa ,
+the default hash function is
+.BR has160 .
+.PP
+Run
+.B dsig show hash
+for a list of supported hash functions.
+.SH "COMMAND REFERENCE"
+.SS help
+The
+.B help
+command behaves exactly as the
+.B \-\-help
+option. With no arguments, it shows an overview of
+.BR dsig 's
+options; with arguments, it describes the named subcommands.
+.SS show
+The
+.B show
+command prints various lists of tokens understood by
+.BR dsig .
+With no arguments, it prints all of the lists; with arguments, it prints
+just the named lists, in order. The recognized lists can be enumerated
+using the
+.VS
+dsig show list
+.VE
+command. The lists are as follows.
+.TP
+.B list
+The lists which can be enumerated by the
+.B show
+command.
+.TP
+.B sig
+The signature algorithms which can be used in a key's
+.B sig
+attribute.
+.TP
+.B hash
+The hash functions which can be used in a key's
+.B hash
+attribute.
+.SS sign
+The
+.B sign
+command creates a signature for a collection of files. The default
+behaviour is to read a list of whitespace-separated file names (see
+below for the precise format) from standard input and write the
+an output file, containing hashes of the files and a digital signature
+made by the key
+.B dsig
+in the current keyring, to standard output, in plain text with binary
+values Base64-encoded. It is intended to be used in conjunction with
+.BR find (1).
+This behaviour can be modified by specifying command-line options.
+.TP
+.B "\-0, \-\-null"
+Read null-terminated filenames, rather than whitespace-separated names.
+This is the recommended mode of operation if you have a
+.BR find (1)
+which understands the
+.B \-print0
+option.
+.TP
+.B "\-b, \-\-binary"
+Produce output in raw binary rather than the textual output. This isn't
+a useful thing to do unless you're trying to debug
+.BR dsig .
+.TP
+.B "\-v, \-\-verbose"
+Makes
+.B dsig
+more verbose. At present, this just means that it'll print the hashes
+of files that it comes across in hex. (Use
+.BR hashsum (1)
+if this is the output you actually wanted.)
+.TP
+.B "\-q, \-\-quiet"
+Makes
+.B dsig
+less verbose.
+.TP
+.BI "\-c, \-\-comment " string
+Writes
+.I string
+as a comment in the output file. The comment's integrity is protected
+by the signature.
+.TP
+.BI "\-f, \-\-file " name
+Read filenames from
+.I name
+instead of from standard input.
+.TP
+.BI "\-o, \-\-output " name
+Write output to
+.I name
+instead of to standard output.
+.TP
+.BI "\-k, \-\-key " tag
+Use the key named
+.I tag
+rather than the default
+.BR dsig .
+.TP
+.BI "\-e, \-\-expire " date
+Set the signature to expire at
+.IR date .
+The default is to expire 28 days from creation. Use
+.B forever
+to make the signature not expire.
+.PP
+The whitespace-separated format for filenames allows quoting and
+escaping of strange characters. The backslash
+.RB ` \e '
+can be used to escape whitespace, quotes, or other special characters
+(including itself), and to represent special characters using the
+standard C escape sequences
+.RB ` \ea ',
+.RB ` \eb ',
+.RB ` \ef ',
+.RB ` \en ',
+.RB ` \et ',
+and
+.RB ` \eb '.
+A filename can be quoted in
+.BR ` ... ',
+.BR ' ... '
+or
+.BR """" ... """".
+Whitespace within quotes is part of the filename. The quotes must be at
+the beginning and end of the name.
+.SS verify
+The
+.B verify
+command will verify signatures made by the
+.B sign
+command. With no arguments, it expects to read a text-format signature
+file from standard input; with an argument, it examines the file it
+names to see whether it's text or binary.
+.PP
+Command-line options provided are:
+.TP
+.B "\-v, \-\-verbose"
+Produce more informational output. The default verbosity level is 1.
+.TP
+.B "\-q, \-\-quiet"
+Produce less information output.
+.PP
+Output is written to standard output in a machine-readable format.
+Formatting errors cause the program to write a diagnostic to standard
+error and exit nonzero as usual. Lines begin with a keyword:
+.TP
+.BI "FAIL " reason
+An error prevented verification.
+.TP
+.BI "BAD " reason
+The signature is bad: some file had the wrong hash or the signature is
+invalid.
+.TP
+.BI "WARN " reason
+.B dsig
+encountered a situation which may or may not invalidate the signature.
+.TP
+.BI "OK " message
+The signature verified correctly.
+.TP
+.BI "INFO " note
+Any other information.
+.PP
+The information written at the various verbosity levels is as follows.
+.hP 0.
+No output. Watch the exit status.
+.B dsig
+exits zero if the signature was good.
+.hP 1.
+All
+.BR OK ,
+.B FAIL
+and
+.B WARN
+messages are printed.
+.hP 2.
+As for level 1; also
+.B BAD
+messages are printed describing reasons why the signature verification
+failed, and an
+.B INFO
+message is printed showing the signature file's comment if any.
+.hP 3.
+As for level 2; also
+.B INFO
+messages are shown listing the signing program's identification string,
+the signing key, the signature and expiry dates, and actual signature
+verification.
+.hP 4.
+As for level 3; also
+.B INFO
+messages are printed for each file covered, showing its name and hash.
+.SH "OUTPUT FORMAT"
+There are two output formats: textual and binary. The hash used in the
+digital signature is always computed on the
+.I binary
+version of the data, regardless of the external representation.
+.SS "Textual format"
+Within the file, whitespace and comments between strings are ignored. A
+comment begins with a hash
+.RB (` # ')
+and extends until the next newline.
+.PP
+Strings are either quoted or whitespace-delimited. A string may be
+quoted by
+.BR ` ... ',
+.BR ' ... '
+or
+.BR """" ... """".
+The end-quote character can be backslash-escaped within the string. An
+occurrence of the unescaped end-quote character terminates the string.
+A whitespace-delimited string is terminated by any unescaped whitespace
+character. The C-language escape sequences
+.RB ` \ea ',
+.RB ` \eb ',
+.RB ` \ef ',
+.RB ` \en ',
+.RB ` \et ',
+and
+.RB ` \eb '
+are recognized within either kind of string.
+.PP
+Blocks within the file consist of sequences of strings. The first
+string is a
+.I tag
+\(en a simple string ending in a colon
+.RB (` : ')
+\(en which describes the format of the remaining strings.
+.SS "Binary format"
+The file consists of a sequence of blocks, each of which begins with a
+tag byte. The format of the test of the block depends on the tag.
+Strings are null-terminated; all integers are in network byte order.
+.PP
+A binary file always begins with an ident block, which has a tag of 0.
+.SS "Block types"
+The following block types are known. They must appear in the order
+given, and except where noted must appear exactly once each.
+.TP
+.BR "ident: " (0)
+Identification string of the generating program.
+.BR "keyid: " (1)
+The signing key's id, as eight hex digits (text) or a 32-bit integer
+(binary).
+.TP
+.BR "comment: " (2)
+The comment string set with the
+.B \-c
+option to the
+.B sign
+command. This block need not appear.
+.TP
+.BR "date: " (3)
+The date the signature was made. In a text file, this has the form
+.IB yyyy-mm-dd
+.IB hh:mm:ss
+.IR timezone ;
+in a binary file, it's a 64-bit integer representing the POSIX time.
+.TP
+.BR "expires: " (4)
+The expiry time of the signature, expressed as for
+.BR date: .
+A non-expiring signature is represented by the string
+.B forever
+in text files, or all-bits-set in binary.
+.TP
+.BR "file: " (5)
+A file hash. In text, this is two strings which are the Base-64-encoded
+hash and the file name; in binary, this is a 16-bit hash length, the raw
+hash, and the null-terminated filename. There can be any number of
+.B file:
+blocks.
+.TP
+.BR "signature: " (6)
+The signature. In text, this is the Base-64-encoded signature; in
+binary, it is a 16-bit length followed by the binary signature.
+.PP
+The signature covers the
+.I binary
+representations of the file's
+.BR date: ,
+.B expires:
+and
+.B file:
+blocks.
+.SH "SEE ALSO"
+.BR key (1),
+.BR hashsum (1),
+.BR catcrypt (1),
+.BR keyring (5).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
/* -*-c-*-
*
- * $Id: dsig.c,v 1.12 2004/04/17 09:58:37 mdw Exp $
+ * $Id$
*
* Verify signatures on distribuitions of files
*
case T_DATE:
case T_EXPIRE:
DENSURE(d, 8);
- STORE32(d->buf + d->len, ((b->t & ~MASK32) >> 16) >> 16);
- STORE32(d->buf + d->len + 4, b->t);
+ if (b->t == KEXP_FOREVER) {
+ STORE32(d->buf + d->len, 0xffffffff);
+ STORE32(d->buf + d->len + 4, 0xffffffff);
+ } else {
+ STORE32(d->buf + d->len, ((b->t & ~MASK32) >> 16) >> 16);
+ STORE32(d->buf + d->len + 4, b->t);
+ }
d->len += 8;
break;
case T_KEYID:
}
}
if (optind != argc || (f & f_bogus))
- die(EXIT_FAILURE, "Usage: sign [-options]");
+ die(EXIT_FAILURE, "Usage: sign [-OPTIONS]");
/* --- Locate the signing key --- */
argc -= optind;
argv += optind;
if ((f & f_bogus) || argc > 1)
- die(EXIT_FAILURE, "Usage: verify [-qv] [file]");
+ die(EXIT_FAILURE, "Usage: verify [-qv] [FILE]");
/* --- Open the key file, and start reading the input file --- */
break;
case T_EXPIRE: {
time_t now = time(0);
- if (b.t < now) {
+ if (b.t != KEXP_FOREVER && b.t < now) {
if (verb > 1)
puts("BAD signature has expired");
f |= f_bogus;
/*----- Main code ---------------------------------------------------------*/
-typedef struct cmd {
- const char *name;
- int (*func)(int /*argc*/, char */*argv*/[]);
- const char *usage;
- const char *help;
-} cmd;
+#define LISTS(LI) \
+ LI("Lists", list, \
+ listtab[i].name, listtab[i].name) \
+ LI("Signature schemes", sig, \
+ sigtab[i].name, sigtab[i].name) \
+ LI("Hash functions", hash, \
+ ghashtab[i], ghashtab[i]->name)
+
+MAKELISTTAB(listtab, LISTS)
+
+int cmd_show(int argc, char *argv[])
+{
+ return (displaylists(listtab, argv + 1));
+}
+
+static int cmd_help(int, char **);
static cmd cmdtab[] = {
+ { "help", cmd_help, "help [COMMAND...]" },
+ { "show", cmd_show, "show [ITEM...]" },
{ "sign", sign,
- "sign [-0bqv] [-c comment] [-k tag] [-e expire] [-f file] [-o output]",
+ "sign [-0bqv] [-c COMMENT] [-k TAG] [-e EXPIRE]\n\t\
+[-f FILE] [-o OUTPUT]",
"\
Options:\n\
\n\
-e, --expire=TIME The signature should expire after TIME.\n\
" },
{ "verify", verify,
- "verify [-qv] [file]", "\
+ "verify [-qv] [FILE]", "\
Options:\n\
\n\
-q, --quiet Produce fewer messages while working.\n\
{ 0, 0, 0 }
};
-/* --- @findcmd@ --- *
- *
- * Arguments: @const char *name@ = a command name
- *
- * Returns: Pointer to the command structure.
- *
- * Use: Looks up a command by name. If the command isn't found, an
- * error is reported and the program is terminated.
- */
-
-static cmd *findcmd(const char *name)
+static int cmd_help(int argc, char **argv)
{
- cmd *c, *chosen = 0;
- size_t sz = strlen(name);
-
- for (c = cmdtab; c->name; c++) {
- if (strncmp(name, c->name, sz) == 0) {
- if (c->name[sz] == 0) {
- chosen = c;
- break;
- } else if (chosen)
- die(EXIT_FAILURE, "ambiguous command name `%s'", name);
- else
- chosen = c;
- }
- }
- if (!chosen)
- die(EXIT_FAILURE, "unknown command name `%s'", name);
- return (chosen);
+ sc_help(cmdtab, stdout, argv + 1);
+ return (0);
}
-static void version(FILE *fp)
+void version(FILE *fp)
{
pquis(fp, "$, Catacomb version " VERSION "\n");
}
static void usage(FILE *fp)
{
- pquis(fp, "Usage: $ [-k keyring] command [args]\n");
+ pquis(fp, "Usage: $ [-k KEYRING] COMMAND [ARGS]\n");
}
-static void help(FILE *fp, char **argv)
+void help_global(FILE *fp)
{
- cmd *c;
-
- if (*argv) {
- c = findcmd(*argv);
- fprintf(fp, "Usage: %s [-k keyring] %s\n", QUIS, c->usage);
- if (c->help) {
- fputc('\n', fp);
- fputs(c->help, fp);
- }
- } else {
- version(fp);
- fputc('\n', fp);
- usage(fp);
- fputs("\n\
+ usage(fp);
+ fputs("\n\
Create and verify signatures on lists of files.\n\
-\n", fp);
- for (c = cmdtab; c->name; c++)
- fprintf(fp, "%s\n", c->usage);
- }
+\n\
+Global command-line options:\n\
+\n\
+-h, --help [COMMAND...] Show this help message, or help for COMMANDs.\n\
+-v, --version Show program version number.\n\
+-u, --usage Show a terse usage message.\n\
+\n\
+-k, --keyring=FILE Read keys from FILE.\n",
+ fp);
}
/* --- @main@ --- *
break;
switch (i) {
case 'h':
- help(stdout, argv + optind);
+ sc_help(cmdtab, stdout, argv + optind);
exit(0);
break;
case 'v':
/* --- Dispatch to the correct subcommand handler --- */
- return (findcmd(argv[0])->func(argc, argv));
+ return (findcmd(cmdtab, argv[0])->cmd(argc, argv));
#undef f_bogus
}
.RB [ \-f0ecbv ]
.RB [ \-a
.IR algorithm ]
+.RB [ \-E
+.IR encoding ]
.IR files ...
.SH DESCRIPTION
The
.B "\-u, \-\-usage"
Prints a brief usage summary to standard output and exits successfully.
.TP
+.BR "\-l, \-\-list " [ \fIitem ...]
+Show lists of hash functions and encodings supported.
+.TP
.BI "\-a, \-\-algorithm=" alg
Use the hash algorithm
.IR alg .
.B "Hashing algorithms"
below.
.TP
-.B "\-l, \-\-list"
-Prints a space-separated list of available hashing algorithms to
-standard output and exits successfully.
+.BI "\-E, \-\-encoding=" encoding
+Use the given
+.I encoding
+to represent hashes in the output. This is not interoperable with other
+programs, but it's handy, e.g., for building sha1 URNs. The encodings
+recognized are
+.B hex
+(the default),
+.B base64
+and
+.BR base32 .
+Type
+.B hashsum \-\-list enc
+for a list of supported encodings.
.TP
.B "\-f, \-\-files"
Each input file is considered to be a list of filenames which should be
Subsequent hashes in this file were generated using the algorithm
.IR alg .
.TP
+.BI "#encoding " encoding
+Subsequent hashes in this file are represented using the named
+.IR encoding .
+.TP
.BI "#escape"
Filenames in subsequence lines are written using the `escaped' format,
described below.
.PP
A
.I "file line"
-consists of a hash, in hexadecimal, followed by a space, a
+consists of a hash, in the requested encoding, followed by a space, a
.IR flag ,
-and the filename. If the current hash algorithm produces
-.IR n -bit
-output, there must be
-.IR n /4
-hex digits of hash in a file line. The
+and the filename. The
.I flag
is either a star
.RB (` * ')
#include <mLib/base64.h>
#include "ghash.h"
+#include "cc.h"
/*----- Static variables --------------------------------------------------*/
/* --- Table --- */
-typedef struct encops {
+typedef struct encodeops {
const char *name;
void (*put)(const octet *, size_t, FILE *);
size_t (*get)(const char *, octet *, size_t, char **);
-} encops;
+} encodeops;
-static const encops enctab[] = {
+static const encodeops encodingtab[] = {
{ "hex", puthex, gethex },
{ "base64", putb64, getb64 },
{ "base32", putb32, getb32 },
{ 0, 0, 0 }
};
-static const encops *getenc(const char *ename)
+static const encodeops *getencoding(const char *ename)
{
- const encops *e;
+ const encodeops *e;
- for (e = enctab; e->name; e++) {
+ for (e = encodingtab; e->name; e++) {
if (strcmp(ename, e->name) == 0)
return (e);
}
/*----- Guts --------------------------------------------------------------*/
static int checkhash(const char *file, unsigned f,
- const gchash *gch, const encops *e)
+ const gchash *gch, const encodeops *e)
{
int rc;
FILE *fp;
xfree(buf);
buf = xmalloc(2 * gch->hashsz);
} else if (strcmp(q, "encoding") == 0) {
- const encops *ee;
+ const encodeops *ee;
if ((q = str_getword(&p)) == 0)
continue;
- if ((ee = getenc(q)) == 0)
+ if ((ee = getencoding(q)) == 0)
continue;
e = ee;
} else if (strcmp(q, "escape") == 0)
}
static int dohash(const char *file, unsigned f,
- const gchash *gch, const encops *e)
+ const gchash *gch, const encodeops *e)
{
int rc = 0;
octet *p = xmalloc(gch->hashsz);
}
static int dofile(const char *file, unsigned f,
- const gchash *gch, const encops *e)
+ const gchash *gch, const encodeops *e)
{
return (f & f_check ? checkhash : dohash)(file, f, gch, e);
}
static int hashfiles(const char *file, unsigned f,
- const gchash *gch, const encops *e)
+ const gchash *gch, const encodeops *e)
{
FILE *fp;
dstr d = DSTR_INIT;
}
static int hashsum(const char *file, unsigned f,
- const gchash *gch, const encops *e)
+ const gchash *gch, const encodeops *e)
{
return (f & f_files ? hashfiles : dofile)(file, f, gch, e);
}
/*----- Main driver -------------------------------------------------------*/
-static void version(FILE *fp)
+void version(FILE *fp)
{
pquis(fp, "$, Catacomb version " VERSION "\n");
}
static void usage(FILE *fp)
{
- pquis(fp, "Usage: $ [-f0ebcv] [-a algorithm] [files...]\n");
+ pquis(fp, "Usage: $ [-f0ebcv] [-a ALGORITHM] [-E ENC] [FILES...]\n");
}
static void help(FILE *fp, const gchash *gch)
-h, --help Display this help message.\n\
-V, --version Display program's version number.\n\
-u, --usage Display a terse usage message.\n\
+-l, --list [ITEM...] Show known hash functions and/or encodings.\n\
\n\
-a, --algorithm=ALG Use the message digest algorithm ALG.\n\
-E, --encoding=ENC Represent hashes using encoding ENC.\n\
fprintf(fp, "The default message digest algorithm is %s.\n", gch->name);
}
+#define LISTS(LI) \
+ LI("Lists", list, listtab[i].name, listtab[i].name) \
+ LI("Hash functions", hash, ghashtab[i], ghashtab[i]->name) \
+ LI("Encodings", enc, encodingtab[i].name, encodingtab[i].name)
+
+MAKELISTTAB(listtab, LISTS)
+
int main(int argc, char *argv[])
{
unsigned f = 0;
const gchash *gch = 0;
- const encops *e = &enctab[0];
+ const encodeops *e = &encodingtab[0];
int rc;
/* --- Initialization --- */
case 'u':
usage(stdout);
exit(0);
+ case 'l':
+ exit(displaylists(listtab, argv + optind));
case 'a':
if ((gch = gethash(optarg)) == 0)
die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg);
f |= f_oddhash;
break;
- case 'l': {
- unsigned j;
- printf("Algorithms: ");
- for (j = 0; ghashtab[j]; j++) {
- if (j) fputc(' ', stdout);
- printf("%s", ghashtab[j]->name);
- }
- fputc('\n', stdout);
- printf("Encodings: ");
- for (j = 0; enctab[j].name; j++) {
- if (j) fputc(' ', stdout);
- printf("%s", enctab[j].name);
- }
- fputc('\n', stdout);
- exit(0);
- } break;
case 'E':
- if ((e = getenc(optarg)) == 0)
+ if ((e = getencoding(optarg)) == 0)
die(EXIT_FAILURE, "unknown encoding `%s'", optarg);
f |= f_oddenc;
break;
. ds ue
. ds *b \fIbeta\fP
.\}
+.de VS
+.sp 1
+.RS
+.nf
+.ft B
+..
+.de VE
+.ft R
+.fi
+.RE
+.sp 1
+..
.TH key 1 "5 June 1999" "Straylight/Edgeware" "Catacomb cryptographic library"
.SH NAME
key \- simple key management system
.I command
is one of:
.PP
+.B help
+.RI [ command ...]
+.br
+.B show
+.RI [ item ...]
+.br
.B add
.RB [ \-lqrLS ]
.RB [ \-a
.IR tag ]
.br
\h'8n'
+.RB [ \-A
+.IR seed-alg ]
+.RB [ \-s
+.IR seed ]
+.RB [ \-n
+.IR bits ]
+.br
+\h'8n'
.RB [ \-e
.IR expire ]
.RB [ \-t
.I "global options"
may be given. The following global options are supported:
.TP
-.BR "\-h, \-\-help " [ \fIcommand ]
+.BR "\-h, \-\-help " [ \fIcommand ...]
Writes a brief summary of
.BR key 's
various options to standard output, and
-returns a successful exit status. With a command name, gives help on
-that command.
+returns a successful exit status. With command names, gives help on
+those commands.
.TP
.B "\-v, \-\-version"
Writes the program's version number to standard output, and returns a
attributes may have meaning for particular applications or key types;
others may be assigned global meanings in future.
.SH "COMMAND REFERENCE"
+.SS help
+The
+.B help
+command behaves exactly as the
+.B \-\-help
+option. With no arguments, it shows an overview of
+.BR key 's
+options; with arguments, it describes the named subcommands.
+.SS show
+The
+.B show
+command prints various lists of tokens understood by
+.BR key .
+With no arguments, it prints all of the lists; with arguments, it prints
+just the named lists, in order. The recognized lists can be enumerated
+using the
+.VS
+key show list
+.VE
+command. The lists are as follows.
+.TP
+.B list
+The lists which can be enumerated by the
+.B show
+command.
+.TP
+.B hash
+The hash functions which can be used with the
+.B fingerprint
+command.
+.TP
+.B ec
+The built-in elliptic curves which can be used with the
+.B add \-a ec
+command.
+.TP
+.B dh
+The built-in Diffie-Hellman groups which can be used with the
+.B add \-a dh
+command.
+.TP
+.B keygen
+The key-generation algorithms which are acceptable to the
+.B \-a
+option of the
+.B add
+command.
+.TP
+.B seed
+The pseudorandom generators which are acceptable to the
+.B \-s
+option of the
+.B add
+command.
.SS add
The
.B add
.BI "\-a, \-\-algorithm " alg
Selects a key generation algorithm. The default algorithm is
.BR binary ;
-the different algorithms are described below.
+the different algorithms are described below. The command
+.B key show keygen
+lists the recognized key-generation algorithms.
.TP
.BI "\-b, \-\-bits " bits
The length of the key to generate, in bits. The default, if this option
key-generation algorithms allow the use of shared parameters. A new key
also inherits attributes from its parameter key.
.TP
+.BI "\-A, \-\-seedalg " seed-alg
+Use the deterministic random number generator algorithm
+.I seed-alg
+to generate the key. Use
+.I before
+the
+.B \-s
+or
+.B \-n
+options; without one of these,
+.B \-A
+has no effect. The default algorithm is
+.BR rmd160-mgf .
+The command
+.B key show seed
+shows a list of recognized seeding algorithms. The seeding algorithm
+used to generate a key is recorded as the key's
+.B seedalg
+attribute.
+.TP
+.BI "\-s, \-\-seed " seed
+Generate the key deterministically using the given
+.IR seed ,
+which should be a Base64-encoded binary string. This is mainly useful
+for parameters keys (types
+.BR dsa-param
+and
+.BR dh-param ),
+to demonstrate that a set of parameters has been generated in an honest
+fashion. The
+.B dsarand
+generation algorithm can be used to generate
+.B dsa-param
+keys as required by FIPS186. The requested seed is recorded,
+Base64-encoded, as the new key's
+.B seed
+attribute.
+.TP
+.BI "\-n, \-\-newseed " bits
+Generate a new seed, with the given length in
+.IR bits .
+The generated seed is recorded, Base64-encoded, as the new key's
+.B seed
+attribute.
+.TP
.BI "\-e, \-\-expire " expire
The expiry date for the generated key. This may be the string
.RB ` forever '
/* -*-c-*-
*
- * $Id: keyutil.c,v 1.25 2004/04/21 00:38:22 mdw Exp $
+ * $Id$
*
* Simple key manager program
*
#include "ptab.h"
#include "rsa.h"
+#include "cc.h"
#include "sha-mgf.h"
#include "sha256-mgf.h"
#include "sha224-mgf.h"
qd_parse qd;
if (strcmp(k->curve, "list") == 0) {
- const pentry *pe;
- printf("Built-in prime groups:\n");
- for (pe = ptab; pe->name; pe++)
- printf(" %s\n", pe->name);
+ unsigned i, w;
+ LIST("Built-in prime groups", stdout, ptab[i].name, ptab[i].name);
exit(0);
}
qd.p = k->curve;
if (!k->bits) k->bits = 256;
if (k->curve && strcmp(k->curve, "list") == 0) {
- const ecentry *ee;
- printf("Built-in elliptic curves:\n");
- for (ee = ectab; ee->name; ee++)
- printf(" %s\n", ee->name);
+ unsigned i, w;
+ LIST("Built-in elliptic curves", stdout,
+ ectab[i].name, ectab[i].name);
exit(0);
}
if (!k->curve) {
if ((k.f & f_bogus) || optind + 1 > argc) {
die(EXIT_FAILURE,
- "Usage: add [options] type [attr...]");
+ "Usage: add [OPTIONS] TYPE [ATTR...]");
}
if (key_chkident(argv[optind]))
die(EXIT_FAILURE, "bad key type `%s'", argv[optind]);
}
if (o.f & f_bogus)
- die(EXIT_FAILURE, "Usage: list [-uqv] [-f filter] [tag...]");
+ die(EXIT_FAILURE, "Usage: list [-uqv] [-f FILTER] [TAG...]");
/* --- Open the key file --- */
int rc = 0;
if (argc < 2)
- die(EXIT_FAILURE, "Usage: expire tag...");
+ die(EXIT_FAILURE, "Usage: expire TAG...");
doopen(&f, KOPEN_WRITE);
for (i = 1; i < argc; i++) {
if ((k = key_bytag(&f, argv[i])) != 0)
int rc = 0;
if (argc < 2)
- die(EXIT_FAILURE, "Usage: delete tag...");
+ die(EXIT_FAILURE, "Usage: delete TAG...");
doopen(&f, KOPEN_WRITE);
for (i = 1; i < argc; i++) {
if ((k = key_bytag(&f, argv[i])) != 0)
key *k;
if (argc < 3)
- die(EXIT_FAILURE, "Usage: setattr tag attr...");
+ die(EXIT_FAILURE, "Usage: setattr TAG ATTR...");
doopen(&f, KOPEN_WRITE);
if ((k = key_bytag(&f, argv[1])) == 0)
die(EXIT_FAILURE, "key `%s' not found", argv[1]);
argv += optind; argc -= optind;
if (rc)
- die(EXIT_FAILURE, "Usage: fingerprint [-f filter] [tag...]");
+ die(EXIT_FAILURE, "Usage: fingerprint [-f FILTER] [TAG...]");
doopen(&f, KOPEN_READ);
int err;
if (argc < 2 || argc > 3)
- die(EXIT_FAILURE, "Usage: comment tag [comment]");
+ die(EXIT_FAILURE, "Usage: comment TAG [COMMENT]");
doopen(&f, KOPEN_WRITE);
if ((k = key_bytag(&f, argv[1])) == 0)
die(EXIT_FAILURE, "key `%s' not found", argv[1]);
argv += optind; argc -= optind;
if (argc < 1 || argc > 2 || rc)
- die(EXIT_FAILURE, "Usage: tag [-r] tag [new-tag]");
+ die(EXIT_FAILURE, "Usage: tag [-r] TAG [NEW-TAG]");
doopen(&f, KOPEN_WRITE);
if (flags & f_retag) {
if ((k = key_bytag(&f, argv[1])) != 0 && strcmp(k->tag, argv[1]) == 0)
dstr d = DSTR_INIT;
if (argc != 2)
- die(EXIT_FAILURE, "Usage: lock qtag");
+ die(EXIT_FAILURE, "Usage: lock QTAG");
doopen(&f, KOPEN_WRITE);
if (key_qtag(&f, argv[1], &d, &k, &kd))
die(EXIT_FAILURE, "key `%s' not found", argv[1]);
dstr d = DSTR_INIT;
if (argc != 2)
- die(EXIT_FAILURE, "Usage: unlock qtag");
+ die(EXIT_FAILURE, "Usage: unlock QTAG");
doopen(&f, KOPEN_WRITE);
if (key_qtag(&f, argv[1], &d, &k, &kd))
die(EXIT_FAILURE, "key `%s' not found", argv[1]);
argv += optind; argc -= optind;
if (rc || argc < 1)
- die(EXIT_FAILURE, "Usage: extract [-f filter] file [tag...]");
+ die(EXIT_FAILURE, "Usage: extract [-f FILTER] FILE [TAG...]");
if (strcmp(*argv, "-") == 0)
fp = stdout;
else if (!(fp = fopen(*argv, "w"))) {
{
key_file f;
if (argc != 1)
- die(EXIT_FAILURE, "usage: tidy");
+ die(EXIT_FAILURE, "Usage: tidy");
doopen(&f, KOPEN_WRITE);
f.f |= KF_MODIFIED; /* Nasty hack */
doclose(&f);
FILE *fp;
if (argc != 2)
- die(EXIT_FAILURE, "Usage: merge file");
+ die(EXIT_FAILURE, "Usage: merge FILE");
if (strcmp(argv[1], "-") == 0)
fp = stdin;
else if (!(fp = fopen(argv[1], "r"))) {
return (0);
}
+/* --- @cmd_show@ --- */
+
+#define LISTS(LI) \
+ LI("Lists", list, \
+ listtab[i].name, listtab[i].name) \
+ LI("Hash functions", hash, \
+ ghashtab[i], ghashtab[i]->name) \
+ LI("Elliptic curves", ec, \
+ ectab[i].name, ectab[i].name) \
+ LI("Diffie-Hellman groups", dh, \
+ ptab[i].name, ptab[i].name) \
+ LI("Key-generation algorithms", keygen, \
+ algtab[i].name, algtab[i].name) \
+ LI("Random seeding algorithms", seed, \
+ seedtab[i].p, seedtab[i].p)
+
+MAKELISTTAB(listtab, LISTS)
+
+static int cmd_show(int argc, char *argv[])
+{
+ return (displaylists(listtab, argv + 1));
+}
+
/*----- Main command table ------------------------------------------------*/
-static struct cmd {
- const char *name;
- int (*cmd)(int /*argc*/, char */*argv*/[]);
- const char *usage;
- const char *help;
-} cmds[] = {
+static int cmd_help(int argc, char *argv[]);
+
+static cmd cmds[] = {
+ { "help", cmd_help, "help [COMMAND...]" },
+ { "show", cmd_show, "show [ITEM...]" },
+ { "list", cmd_list, "list [-uqv] [-f FILTER] [TAG...]", "\
+Options:\n\
+\n\
+-u, --utc Display expiry times etc. in UTC, not local time.\n\
+-q, --quiet Show less information.\n\
+-v, --verbose Show more information.\n\
+" },
+ { "fingerprint", cmd_finger, "fingerprint [-f FILTER] [TAG...]", "\
+Options:\n\
+\n\
+-f, --filter=FILT Only hash key components matching FILT.\n\
+-a, --algorithm=HASH Use the named HASH algorithm.\n\
+ ($ show hash for list.)\n\
+" },
+ { "extract", cmd_extract, "extract [-f FILTER] FILE [TAG...]", "\
+Options:\n\
+\n\
+-f, --filter=FILT Only extract key components matching FILT.\n\
+" },
+ { "merge", cmd_merge, "merge FILE" },
+ { "expire", cmd_expire, "expire TAG..." },
+ { "delete", cmd_delete, "delete TAG..." },
+ { "setattr", cmd_setattr, "setattr TAG ATTR..." },
+ { "comment", cmd_comment, "comment TAG [COMMENT]" },
+ { "lock", cmd_lock, "lock QTAG" },
+ { "unlock", cmd_unlock, "unlock QTAG" },
+ { "tag", cmd_tag, "tag [-r] TAG [NEW-TAG]", "\
+Options:\n\
+\n\
+-r, --retag Untag any key currently called new-tag.\n\
+" },
+ { "tidy", cmd_tidy, "tidy" },
{ "add", cmd_add,
- "add [options] type [attr...]\n\
- Options: [-lqrLS] [-a alg] [-bB bits] [-p param] [-R tag]\n\
- [-e expire] [-t tag] [-c comment]", "\
+ "add [-OPTIONS] TYPE [ATTR...]\n\
+ Options: [-lqrLS] [-a ALG] [-bB BITS] [-p PARAM] [-R TAG]\n\
+ [-A SEEDALG] [-s SEED] [-n BITS]\n\
+ [-e EXPIRE] [-t TAG] [-c COMMENT]", "\
Options:\n\
\n\
-a, --algorithm=ALG Generate keys suitable for ALG.\n\
+ ($ show keygen for list.)\n\
-b, --bits=N Generate an N-bit key.\n\
-B, --qbits=N Use an N-bit subgroup or factors.\n\
-p, --parameters=TAG Get group parameters from TAG.\n\
--C, --curve=CURVE Use elliptic curve CURVE.\n\
+-C, --curve=NAME Use elliptic curve or DH group NAME.\n\
+ ($ show ec or $ show dh for list.)\n\
+-A, --seedalg=ALG Use pseudorandom generator ALG to generate key.\n\
+ ($ show seed for list.)\n\
+-s, --seed=BASE64 Use Base64-encoded string BASE64 as seed.\n\
+-n, --newseed=COUNT Generate new COUNT-bit seed.\n\
-e, --expire=TIME Make the key expire after TIME.\n\
-c, --comment=STRING Attach the command STRING to the key.\n\
-t, --tag=TAG Tag the key with the name TAG.\n\
-L, --lim-lee Generate Lim-Lee primes for Diffie-Hellman groups.\n\
-S, --subgroup Use a prime-order subgroup for Diffie-Hellman.\n\
" },
- { "expire", cmd_expire, "expire tag..." },
- { "delete", cmd_delete, "delete tag..." },
- { "tag", cmd_tag, "tag [-r] tag [new-tag]", "\
-Options:\n\
-\n\
--r, --retag Untag any key currently called new-tag.\n\
-" },
- { "setattr", cmd_setattr, "setattr tag attr..." },
- { "comment", cmd_comment, "comment tag [comment]" },
- { "lock", cmd_lock, "lock qtag" },
- { "unlock", cmd_unlock, "unlock qtag" },
- { "list", cmd_list, "list [-uqv] [-f filter] [tag...]", "\
-Options:\n\
-\n\
--u, --utc Display expiry times etc. in UTC, not local time.\n\
--q, --quiet Show less information.\n\
--v, --verbose Show more information.\n\
-" },
- { "fingerprint", cmd_finger, "fingerprint [-f filter] [tag...]", "\
-Options:\n\
-\n\
--f, --filter=FILT Only hash key components matching FILT.\n\
--a, --algorithm=HASH Use the named HASH algorithm.\n\
-" },
- { "tidy", cmd_tidy, "tidy" },
- { "extract", cmd_extract, "extract [-f filter] file [tag...]", "\
-Options:\n\
-\n\
--f, --filter=FILT Only extract key components matching FILT.\n\
-" },
- { "merge", cmd_merge, "merge file" },
{ 0, 0, 0 }
};
-typedef struct cmd cmd;
-
-/*----- Main code ---------------------------------------------------------*/
-
-/* --- @findcmd@ --- *
- *
- * Arguments: @const char *name@ = a command name
- *
- * Returns: Pointer to the command structure.
- *
- * Use: Looks up a command by name. If the command isn't found, an
- * error is reported and the program is terminated.
- */
-
-static cmd *findcmd(const char *name)
+static int cmd_help(int argc, char *argv[])
{
- cmd *c, *chosen = 0;
- size_t sz = strlen(name);
-
- for (c = cmds; c->name; c++) {
- if (strncmp(name, c->name, sz) == 0) {
- if (c->name[sz] == 0) {
- chosen = c;
- break;
- } else if (chosen)
- die(EXIT_FAILURE, "ambiguous command name `%s'", name);
- else
- chosen = c;
- }
- }
- if (!chosen)
- die(EXIT_FAILURE, "unknown command name `%s'", name);
- return (chosen);
+ sc_help(cmds, stdout, argv + 1);
+ return (0);
}
+/*----- Main code ---------------------------------------------------------*/
+
/* --- Helpful GNUy functions --- */
-void usage(FILE *fp)
+static void usage(FILE *fp)
{
- pquis(fp, "Usage: $ [-k keyring] command [args]\n");
+ pquis(fp, "Usage: $ [-k KEYRING] COMMAND [ARGS]\n");
}
void version(FILE *fp)
pquis(fp, "$, Catacomb version " VERSION "\n");
}
-void help(FILE *fp, char **argv)
+void help_global(FILE *fp)
{
- cmd *c;
-
- version(fp);
- fputc('\n', fp);
- if (*argv) {
- c = findcmd(*argv);
- fprintf(fp, "Usage: %s [-k keyring] %s\n", QUIS, c->usage);
- if (c->help) {
- fputc('\n', fp);
- fputs(c->help, fp);
- }
- } else {
- usage(fp);
- fputs("\n\
-Performs various simple key management operations. Command line options\n\
-recognized are:\n\
+ usage(fp);
+ fputs("\n\
+Performs various simple key management operations.\n\
+\n\
+Global command line options:\n\
\n\
--h, --help [COMMAND] Display this help text (or help for COMMAND).\n\
+-h, --help [COMMAND...] Display this help text (or help for COMMANDs).\n\
-v, --version Display version number.\n\
-u, --usage Display short usage summary.\n\
\n\
--k, --keyring=FILE Read and write keys in FILE.\n\
--i, --id=TAG Use key TAG for random number generator.\n\
--t, --type=TYPE Use key TYPE for random number generator.\n\
-\n\
-The following commands are understood:\n\n",
- fp);
- for (c = cmds; c->name; c++)
- fprintf(fp, "%s\n", c->usage);
- }
+-k, --keyring=FILE Read and write keys in FILE.\n",
+ fp);
}
/* --- @main@ --- *
/* --- GNU help options --- */
case 'h':
- help(stdout, argv + optind);
+ sc_help(cmds, stdout, argv + optind);
exit(0);
case 'v':
version(stdout);
argc -= optind;
argv += optind;
optind = 0;
- return (findcmd(argv[0])->cmd(argc, argv));
+ return (findcmd(cmds, argv[0])->cmd(argc, argv));
}
/*----- That's all, folks -------------------------------------------------*/
/* -*-c-*-
*
- * $Id: perftest.c,v 1.1 2004/04/21 00:37:32 mdw Exp $
+ * $Id$
*
* Measure performance of various operations (Unix-specific)
*
#include "ec.h"
#include "group.h"
+#include "cc.h"
#include "gcipher.h"
#include "ghash.h"
#include "gmac.h"
+#include "ectab.h"
+#include "ptab.h"
/*----- Options -----------------------------------------------------------*/
/* --- Job table --- */
-typedef struct jobobs {
+typedef struct jobops {
const char *name;
void *(*init)(opts *);
void (*run)(void *);
/*----- Main code ---------------------------------------------------------*/
-static void version(FILE *fp)
+void version(FILE *fp)
{
pquis(fp, "$, Catacomb " VERSION "\n");
}
usage(fp);
pquis(fp, "\n\
Various performance tests.\n\
+\n\
+Options:\n\
+\n\
+-h, --help Show this help text.\n\
+-v, --version Show program version number.\n\
+-u, --usage Show terse usage message.\n\
+-l, --list [ITEM...] List all the various names of things.\n\
+\n\
+-C, --name=NAME Select curve/DH-group/enc/hash name.\n\
+-b, --field-bits Field size for g-prime and rsa.\n\
+-B, --group-bits Group size for g-prime; key size for ksched;\n\
+ data size for enc and hash.\n\
+-n, --factors=COUNT Number of factors for {exp,mul}-sim.\n\
+-i, --intervals=COUNT Number of intervals to run for. [0; forever]\n\
+-t, --time=TIME Length of an interval in seconds. [1]\n\
");
}
+#define LISTS(LI) \
+ LI("Lists", list, \
+ listtab[i].name, listtab[i].name) \
+ LI("Jobs", job, \
+ jobtab[i].name, jobtab[i].name) \
+ LI("Elliptic curves", ec, \
+ ectab[i].name, ectab[i].name) \
+ LI("Diffie-Hellman groups", dh, \
+ ptab[i].name, ptab[i].name) \
+ LI("Encryption algorithms", cipher, \
+ gciphertab[i], gciphertab[i]->name) \
+ LI("Hash functions", hash, \
+ ghashtab[i], ghashtab[i]->name)
+
+MAKELISTTAB(listtab, LISTS)
+
static unsigned uarg(const char *what, const char *p)
{
char *q;
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "usage", 0, 0, 'u' },
+ { "list", 0, 0, 'l' },
{ "name", OPTF_ARGREQ, 0, 'C' },
{ "field-bits", OPTF_ARGREQ, 0, 'b' },
{ "group-bits", OPTF_ARGREQ, 0, 'B' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "hvuC:b:B:n:i:t:", opts, 0, 0, 0);
+ i = mdwopt(argc, argv, "hvulC:b:B:n:i:t:", opts, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'h': help(stdout); exit(0);
case 'v': version(stdout); exit(0);
case 'u': usage(stdout); exit(0);
+ case 'l': exit(displaylists(listtab, argv + optind));
case 'C': o.name = optarg; break;
case 'b': o.fbits = uarg("field bits", optarg); break;
case 'B': o.gbits = uarg("subgroup bits", optarg); break;