]> pd.if.org Git - zpackage/blob - crypto/libeddsa/sign.c
move blake2 out of subdirectory
[zpackage] / crypto / libeddsa / sign.c
1 #define _POSIX_C_SOURCE 200809L
2
3 /* general zpm sign function */
4
5 /* read key, export key, import key, sign, export signature, import
6  * signature, verify signature
7  */
8
9 /* import and export is base64 encoded */
10
11 /* -v verify
12  * -s sign
13  * -g generate key
14  * -e extract public key
15  *
16  * -o output file
17  *
18  * -p read key from file
19  * -P read public key from argument to -P
20  * -S read secret key from argument
21  * -m message from argument
22  * -h message is hex encoded
23  */
24
25 /* chacha20 encryption: 256 bit key = 32 bytes */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include <time.h>
37
38 /* linux specific for getrandom */
39 #include <sys/random.h>
40
41 #include "eddsa.h"
42 #include "sha512.h"
43 #include "crypto/chacha.h"
44 #include "lib/blake2.h"
45
46 char *readpass(char *prompt);
47
48 #define VERIFY 1
49 #define SIGN 2
50 #define KEYGEN 3
51 #define EXTRACT 4
52 #define KEYSIGN 5
53 #define LIST 6
54 #define ENCRYPT 7
55 #define DECRYPT 8
56 #define SIGNKEY 9
57 #define IMPORT 10 
58
59 /* output flags */
60 #define RAW 0x1
61 #define HUMANREADABLE 0x2
62
63 #define SECRET_KEY 1
64 #define PUBLIC_KEY 2
65 #define SIGNATURE 3
66 #define UNKNOWN 4
67
68 #define VERSION 1
69
70 /* possible additional types:
71  * designated revoker
72  * revocation certificate
73  */
74
75 /* timestamps are 8 byte little endian integers of seconds since
76  * the epoch.  or unix time, or some such.  Times are a mess.
77  * Unix time is leap second unaware, and ambiguous during leap seconds.
78  * UTC requires a database of leap seconds for past time, and the
79  * specified second in the future possibly changes.
80  * TAI is good, but currently 37 seconds behind UTC, which is just weird
81  */
82
83 /* size of structs would have to be increased for 57/64 byte keys
84  * and key*2 size signatures
85  */
86
87 /* need 25 more bytes for ed448 */
88 struct secret_key {
89         char magic[4]; /* "ZPMS" */
90         uint8_t version; /* 0x01 */
91         uint8_t type; /* 0x01 */
92         uint8_t encryption; /* 0x01 == chacha */
93         uint8_t reserved1; /* MBZ */
94         char key[32]; /* private key data */
95         int64_t created; /* time in unix epoch seconds, little endian */
96         int64_t expires; /* time in unix epoch seconds, little endian, = is none, could do uint64max */
97         char salt[8]; /* password salt, nist wants 16, but we're not using nist approved hash algorithms anyway. */
98         char reserved2[64]; /* could put the pubkey here could have 16 bytes of IV for chacha to encrypt. */
99         char id[120]; /* 1 byte len, id bytes, zero bytes remainder */
100         char trailer[8]; /* room for a pointer */
101 };
102
103 struct public_key {
104         char magic[4]; /* "ZPMS" */
105         uint8_t version; /* 0x01 */
106         uint8_t type; /* 0x02 */
107         uint8_t reserved0; /* MBZ */
108         uint8_t reserved1; /* MBZ */
109         char key[32]; /* public key data */
110         int64_t created; /* time in unix epoch seconds, little endian */
111         int64_t expires; /* time in unix epoch seconds, little endian */
112         char reserved2[8]; /* MBZ */
113         char signature[64]; /* self sig data */
114         char id[120]; /* 1 byte len, id bytes, zero bytes remainder */
115         char trailer[8]; /* room for a pointer */
116 };
117
118 struct signature {
119         char magic[4]; /* "ZPMS" */
120         uint8_t version; /* 0x01 */
121         uint8_t type; /* 0x03 */
122         uint8_t reserved0; /* MBZ */ /* trust level? revokable? */
123         uint8_t reserved1; /* MBZ */
124         char key[32]; /* signing public key data?, can be zero */
125         int64_t signtime; /* time in unix epoch seconds, little endian */
126         int64_t expires; /* time in unix epoch seconds, little endian */
127         char reserved2[8]; /* MBZ */
128         char signature[64]; /* sig data */
129         char reserved3[120]; /* some indication of what you're signing ? */
130         /* 512 bits is 64 bytes, could put the hash of the data signed */
131         char trailer[8]; /* room for a pointer */
132 };
133
134 struct keysig {
135         char magic[4]; /* "ZPMS" */
136         uint8_t version; /* 0x01 */
137         uint8_t type;
138         uint8_t encryption; /* trust level for pk? revokable for sig? */
139         uint8_t reserved1; /* MBZ */
140         char key[32]; /* signing public key data?, can be zero */
141         /* should these be signed? */
142         int64_t created; /* time in unix epoch seconds */
143         int64_t expires; /* time in unix epoch seconds */
144         char salt[8]; /* reserved for pk and sig, could be IV for sig */
145         char signature[64]; /* sig data, reserved for sk */
146         char id[120]; /* signing hash for sig? otherwise reserved for sig */
147         /* 512 bits is 64 bytes, could put the hash of the data signed */
148         char trailer[8]; /* room for a pointer */
149 };
150
151 struct signing_context {
152         char *message;
153         size_t mlen;
154
155         char *keyfile, *keystring, *keyid, *keyprefix, *passphrase;
156         unsigned char passkey[32];
157 };
158
159 void putsle8(unsigned char *dst, int64_t inval) {
160         int i;
161         union { uint64_t out; int64_t in; } uv;
162         uint64_t val;
163
164         uv.in = inval;
165         val = uv.out;
166
167         for (i=0; i<8; i++) {
168                 dst[i] = val & 0xff;
169                 val >>= 8;
170         }
171 }
172
173 int64_t getsle8(unsigned char *dst) {
174         uint64_t val = 0;
175         int i;
176         union { int64_t out; uint64_t in; } uv;
177
178         for (i=0; i<8; i++) {
179                 val += (uint64_t)dst[i] << (8*i);
180         }
181
182         uv.in = val;
183
184         return uv.out;
185 }
186
187 void seckey_bytea(unsigned char *bytes, struct secret_key *sk) {
188         memset(bytes, 0, 256);
189         memcpy(bytes, "ZPMS", 4);
190         bytes[4] = sk->version;
191         bytes[5] = sk->type;
192         bytes[6] = sk->encryption;
193         /* 7 reserved */
194         memcpy(bytes + 8, sk->key, 32);
195         putsle8(bytes+40, sk->created);
196         putsle8(bytes+48, sk->expires);
197         /* @56 8 salt, not implemented */
198         /* memcpy(bytes + 64, sk->reserved2, 64); should probably put the pk */
199         memcpy(bytes + 128, sk->id, 120);
200         /* 8 reserved */
201 }
202
203 void bytea_seckey(struct secret_key *sk, unsigned char *bytes) {
204         memcpy(sk->magic, bytes, 4);
205         sk->version = bytes[4];
206         sk->type = bytes[5]; 
207         sk->encryption = bytes[6];
208         sk->reserved1 = 0;
209         memcpy(sk->key, bytes + 8, 32);
210         sk->created = getsle8(bytes+40);
211         sk->expires = getsle8(bytes+48);
212         memset(sk->salt, 0, 8); /* salt not implemented */
213         memset(sk->reserved2, 0, 64); /* salt not implemented */
214         memcpy(sk->id, bytes + 128, 120);
215         memset(sk->trailer, 0, 8);
216 }
217
218 int create_key(struct secret_key *sk, int generate) {
219         memcpy(sk->magic, "ZPMS", 4);
220         sk->version = VERSION;
221         sk->type = SECRET_KEY;
222         sk->encryption = 0;
223         sk->reserved1 = 0;
224
225         if (generate) {
226                 /* a private key is just 32 random bytes */
227                 getrandom(sk->key, sizeof sk->key, 0);
228         }
229
230         sk->created = time(NULL);
231         sk->expires = INT64_MAX;
232         memset(sk->salt, 0, 8);
233         memset(sk->reserved2, 0, 64);
234         memset(sk->id, 0, 120);
235         memset(sk->trailer, 0, 8);
236
237         ed25519_genpub(sk->reserved2, sk->key);
238         return 1;
239 }
240
241 /* hash password into 32 bytes for chacha encryption */
242 int collect_key(unsigned char *key, const char *pass) {
243         struct blake2b_state__ h;
244         if (!pass) {
245                 pass = readpass("Passphrase: ");
246         }
247
248         if (!pass) {
249                 return 0;
250         }
251
252         blake2b_init(&h, 32);
253         blake2b_update(&h, pass, strlen(pass));
254         blake2b_final(&h, key, 32);
255         return 1;
256 }
257
258 int encrypt_key(struct secret_key *sk, unsigned char *key) {
259         int i;
260
261         if (sk->encryption) {
262                 return 1;
263         }
264
265         /* TODO chacha encrypt sk->key */
266         for (i=0; i < 32; i++) {
267                 sk->key[i] ^= key[i];
268         }
269
270         sk->encryption = 1;
271         return 1;
272 }
273
274 int encrypt_sk(struct secret_key *sk, unsigned char *pass) {
275         unsigned char key[32];
276
277         if (sk->encryption == 1) {
278                 return 1;
279         }
280
281         collect_key(key, pass);
282         encrypt_key(sk, key);
283
284         memset(key, 0, 32);
285         memset(pass, 0, strlen(pass));
286
287         return 1;
288 }
289
290 int decrypt_sk(struct secret_key *sk, unsigned char *pass) {
291         unsigned char key[32];
292         int i;
293
294         if (sk->encryption == 0) {
295                 return 1;
296         }
297
298         collect_key(key, pass);
299
300         for (i=0; i < 32; i++) {
301                 sk->key[i] ^= key[i];
302         }
303
304         memset(key, 0, 32);
305         memset(pass, 0, strlen(pass));
306
307         sk->encryption = 0;
308
309         return 1;
310 }
311
312 int decrypt_key(struct secret_key *sk, unsigned char *key) {
313         int i;
314
315         if (sk->encryption == 0) {
316                 return 1;
317         }
318
319         /* TODO chacha decrypt sk->key */
320         for (i=0; i < 32; i++) {
321                 sk->key[i] ^= key[i];
322         }
323
324         sk->encryption = 0;
325         return 1;
326 }
327
328 void pubkey_init(struct public_key *pk) {
329         memcpy(pk->magic, "ZPMS", 4);
330         pk->version = VERSION;
331         pk->type = PUBLIC_KEY;
332         pk->reserved0 = 0;
333         pk->reserved1 = 0;
334         memset(pk->key, 0, sizeof pk->key);
335         pk->created = 0;
336         pk->expires = 0;
337         memset(pk->reserved2, 0, 8);
338         memset(pk->signature, 0, 64);
339         memset(pk->id, 0, 120);
340         memset(pk->trailer, 0, 8);
341 }
342
343 void pubkey_bytea(unsigned char *bytes, struct public_key *pk) {
344         memset(bytes, 0, 256);
345         memcpy(bytes, "ZPMS", 4);
346         bytes[4] = pk->version;
347         bytes[5] = pk->type;
348         /* 6 7 reserved */
349         memcpy(bytes + 8, pk->key, 32);
350         putsle8(bytes+40, pk->created);
351         putsle8(bytes+48, pk->expires);
352         /* @56 8 reserved */
353         memcpy(bytes + 64, pk->signature, 64);
354         memcpy(bytes + 128, pk->id, 120);
355         /* 8 reserved */
356 }
357
358 void bytea_pubkey(struct public_key *pk, unsigned char *bytes) {
359         memcpy(pk->magic, bytes, 4);
360         pk->version = bytes[4];
361         pk->type = bytes[5]; 
362         pk->reserved0 = 0;
363         pk->reserved1 = 0;
364         memcpy(pk->key, bytes + 8, 32);
365         pk->created = getsle8(bytes+40);
366         pk->expires = getsle8(bytes+48);
367         memset(pk->reserved2, 0, 8);
368         memcpy(pk->signature, bytes + 64, 64);
369         memcpy(pk->id, bytes + 128, 120);
370         memset(pk->trailer, 0, 8);
371 }
372
373 int derive_pubkey(struct public_key *pk, struct secret_key *sk) {
374         char bytes[256];
375
376         memcpy(pk->magic, "ZPMS", 4);
377         pk->version = VERSION;
378         pk->type = PUBLIC_KEY;
379         pk->reserved0 = 0;
380         pk->reserved1 = 0;
381         ed25519_genpub(pk->key, sk->key);
382         pk->created = sk->created;
383         pk->expires = sk->expires;
384         memset(pk->reserved2, 0, 8);
385         memset(pk->signature, 0, 64);
386         memset(pk->id, 0, 120);
387         strncpy(pk->id, sk->id, 119);
388         memset(pk->trailer, 0, 8);
389
390         /* serialize and sign */
391         pubkey_bytea(bytes, pk);
392         ed25519_sign(pk->signature, sk->key, pk->key, bytes, 256);
393
394         return 1;
395 }
396
397 void bytea_signature(struct signature *sig, unsigned char *bytes) {
398         memcpy(sig->magic, bytes, 4);
399         sig->version = bytes[4];
400         sig->type = bytes[5]; 
401         sig->reserved0 = 0;
402         sig->reserved1 = 0;
403         memcpy(sig->key, bytes + 8, 32);
404         sig->signtime = getsle8(bytes+40);
405         sig->expires = getsle8(bytes+48);
406         memset(sig->reserved2, 0, 8);
407         memcpy(sig->signature, bytes + 64, 64);
408         memcpy(sig->reserved3, bytes + 128, 120);
409         memset(sig->trailer, 0, 8);
410 }
411
412 void signature_bytea(unsigned char *bytes, struct signature *sig) {
413         memset(bytes, 0, 256);
414         memcpy(bytes, "ZPMS", 4);
415         bytes[4] = sig->version;
416         bytes[5] = sig->type;
417         /* 6 7 reserved */
418         memcpy(bytes + 8, sig->key, 32);
419         putsle8(bytes+40, sig->signtime);
420         putsle8(bytes+48, sig->expires);
421         /* @56 8 reserved */
422         memcpy(bytes + 64, sig->signature, 64);
423         /* 120 reserved */
424         /* 8 reserved */
425 }
426
427 union signobject {
428         struct signature sig;
429         struct public_key pk;
430         struct secret_key sk;
431         char bytes[256];
432 };
433
434 int object_type(union signobject *obj) {
435         return obj ? obj->sk.type : 0;
436 }
437
438 void sighash(unsigned char *dst, struct signature *sig, unsigned char *data,
439                 size_t len) {
440         unsigned char signtime[8], expires[8];
441         struct sha512 hash;
442
443         /* need to put these in as little endian */
444         putsle8(signtime, sig->signtime);
445         putsle8(expires, sig->expires);
446
447         sha512_init(&hash);
448         sha512_add(&hash, signtime, sizeof signtime);
449         sha512_add(&hash, expires, sizeof expires);
450         sha512_add(&hash, data, len);
451         sha512_final(&hash, dst);
452 }
453
454 void init_signature(struct signature *sig) {
455         memcpy(sig->magic, "ZPMS", 4);
456         sig->version = VERSION;
457         sig->type = SIGNATURE;
458         sig->reserved0 = 0;
459         sig->reserved1 = 0;
460         memset(sig->key, 0, sizeof sig->key);
461         sig->signtime = 0;
462         sig->expires = 0;
463         memset(sig->reserved2, 0, 8);
464         memset(sig->signature, 0, 64);
465         memset(sig->reserved3, 0, 120);
466         memset(sig->trailer, 0, 8);
467 }
468
469 int create_signature(struct signature *sig, struct secret_key *sk,
470                 int baresign, unsigned char *data, size_t len) {
471         unsigned char messagehash[64];
472
473         if (!sk || !data || !sig) {
474                 return 0;
475         }
476
477         memcpy(sig->magic, "ZPMS", 4);
478         sig->version = VERSION;
479         sig->type = SIGNATURE;
480         sig->reserved0 = 0;
481         sig->reserved1 = 0;
482         ed25519_genpub(sig->key, sk->key);
483 #if 0
484         sig->signtime = 0;
485         sig->expires = 0;
486 #endif
487         memset(sig->reserved2, 0, 8);
488         memset(sig->signature, 0, 64);
489         memset(sig->reserved3, 0, 120);
490         memset(sig->trailer, 0, 8);
491
492         if (!baresign) {
493                 sighash(messagehash, sig, data, len);
494                 data = messagehash;
495                 len = sizeof messagehash;
496         }
497
498         ed25519_sign(sig->signature, sk->key, sig->key, data, len);
499
500         return 1;
501 }
502
503 //#define MARK do { fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__); } while (0)
504
505 static char hexchars[] = "0123456789abcdefABCDEF";
506
507 static void hex(char *dst, uint8_t *src, size_t len) {
508         while (len--) {
509                 dst[0] = hexchars[(src[0]>>4)&0xf];
510                 dst[1] = hexchars[src[0]&0xf];
511                 dst+=2;
512                 src++;
513         }
514 }
515
516 /* always 512 bytes dst, 248 bytes src, last 8 bytes
517  * are ignored and set to zero, last 4 bytes not output
518  */
519 void serialize(uint8_t *dst, unsigned char *src) {
520         int i;
521         uint8_t byte, hi, lo;
522
523         for (i = 0; i < 248; i++) {
524                 byte = src[i];
525                 hi = byte >> 4;
526                 lo = byte & 0xf;
527                 if (i % 32 == 0 && i > 0) {
528                         *dst++ = '\n';
529                 }
530
531                 *dst++ = hexchars[hi];
532                 *dst++ = hexchars[lo];
533         }
534         for (; i < 252; i++) {
535                 *dst++ = '0';
536                 *dst++ = '0';
537         }
538         *dst++ = '\n';
539 }
540
541 int hexval(int digit) {
542         if (digit >= '0' && digit <= '9') {
543                 return digit - '0';
544         } else if (digit == 'A' || digit == 'a') {
545                 return 10;
546         } else if (digit == 'B' || digit == 'b') {
547                 return 11;
548         } else if (digit == 'C' || digit == 'c') {
549                 return 12;
550         } else if (digit == 'D' || digit == 'd') {
551                 return 13;
552         } else if (digit == 'E' || digit == 'e') {
553                 return 14;
554         } else if (digit == 'F' || digit == 'f') {
555                 return 15;
556         }
557
558         return 0;
559 }
560
561 /* convert at most dlen hex bytes from srclen, returns
562  * number of bytes read, src may contain zero bytes,
563  * so use strlen in the caller if needed
564  */ 
565 size_t hex2bin(uint8_t *dst, size_t dlen, char *src, size_t slen) {
566         size_t i, n = 0;
567         uint8_t val = 0;
568
569         for (i = 0; i < slen && n < dlen; i++) {
570                 if (!isxdigit(src[i])) {
571                         continue;
572                 }
573
574                 val = hexval(src[i++]) << 4;
575                 /* look for next hex digit */
576                 while (i < slen && !isxdigit(src[i])) {
577                         i++;
578                 }
579                 if (i == slen || !isxdigit(src[i])) {
580                         break; /* tests redundant, but make code clearer */
581                 }
582                 val += hexval(src[i]); /* low nibble */
583                 dst[n++] = val;
584         }
585
586         return n;
587 }
588
589 /* read in up to 248 bytes, set remaining to zero
590  * returns byte 5 if the bytes begin with "ZPMS" and 248 bytes were converted
591  * src must be at least 512 bytes
592  */
593 int deserialize(void *obj, uint8_t *src, size_t slen) {
594         int bytes, i, type;
595         char buf[256];
596
597         bytes = hex2bin(buf, 248, src, slen);
598
599         for (i = bytes; i < 256; i++) {
600                 buf[i] = 0;
601         }
602
603         if (bytes == 248 && memcmp(buf, "ZPMS", 4) == 0) {
604                 type = buf[5];
605         } else {
606                 return 0;
607         }
608
609         switch(type) {
610                 case SECRET_KEY:
611                         bytea_seckey(obj, buf);
612                         memset(buf, 0, sizeof buf);
613                         break;
614                 case PUBLIC_KEY:
615                         bytea_pubkey(obj, buf);
616                         break;
617                 case SIGNATURE:
618                         bytea_signature(obj, buf);
619                         break;
620                 default:
621                         type = UNKNOWN;
622                         break;
623         }
624
625         return type;
626 }
627
628 void *map(char *file, size_t *size) {
629         int fd, rv;
630         void *m;
631         struct stat st;
632
633         fd = open(file, O_RDONLY);
634         if (fd == -1) {
635                 return NULL;
636         }
637
638         rv = fstat(fd, &st);
639         if (rv == -1) {
640                 close(fd);
641                 return NULL;
642         }
643
644         m = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
645         if (m == MAP_FAILED) {
646                 return 0;
647         }
648
649         close(fd);
650         *size = st.st_size;
651         return m;
652 }
653
654 /* read 512 bytes from fd, returns -1 for error, 512 for full read,
655  * < 512 for end of file
656  */
657 ssize_t read512(int fd, void *dst) {
658         ssize_t bytes = 0;
659         ssize_t need = 512;
660         while (need) {
661                 bytes = read(fd, dst + 512 - need, need);
662                 if (bytes == -1) {
663                         return -1;
664                 }
665                 if (bytes == 0) {
666                         return 512 - need;
667                 }
668                 need -= bytes;
669         }
670         return 512;
671 }
672
673 int read_item(int fd, void *item) {
674         char buffer[512];
675         ssize_t bytes;
676         int type;
677
678         bytes = read512(fd, buffer);
679         if (bytes != 512) {
680                 return 0;
681         }
682         type = deserialize(item, buffer, sizeof buffer);
683         return type;
684 }
685
686 int write_secret_key(int fd, struct secret_key *sk, int outputflags) {
687         uint8_t skh[256];
688         char serialized[512];
689         size_t outlen;
690
691         if (outputflags & RAW) {
692                 hex(serialized, sk->key, 32);
693                 outlen = 64;
694         } else {
695                 seckey_bytea(skh, sk);
696                 serialize(serialized, skh);
697                 outlen = sizeof serialized;
698         }
699
700         write(fd, serialized, outlen);
701         /* clear memory */
702         memset(skh, 0, sizeof skh);
703         memset(serialized, 0, sizeof serialized);
704
705         return 1;
706 }
707
708 int write_public_key(int fd, struct public_key *pk, int outputflags) {
709         uint8_t skh[256];
710         char serialized[512];
711         size_t outlen;
712
713         if (outputflags & RAW) {
714                 hex(serialized, pk->key, 32);
715                 outlen = 64;
716         } else {
717                 pubkey_bytea(skh, pk);
718                 serialize(serialized, skh);
719                 outlen = sizeof serialized;
720         }
721
722         write(fd, serialized, outlen);
723         /* clear memory */
724         memset(skh, 0, sizeof skh);
725         memset(serialized, 0, sizeof serialized);
726
727         return 1;
728 }
729
730 int write_signature(int fd, struct signature *sig, int outputflags) {
731         uint8_t skh[256];
732         char serialized[512];
733         size_t outlen;
734
735         if (outputflags & RAW) {
736                 hex(serialized, sig->signature, 64);
737                 outlen = 128;
738         } else {
739                 signature_bytea(skh, sig);
740                 serialize(serialized, skh);
741                 outlen = sizeof serialized;
742         }
743
744         write(fd, serialized, outlen);
745         /* clear memory */
746         memset(skh, 0, sizeof skh);
747         memset(serialized, 0, sizeof serialized);
748
749         return 1;
750 }
751
752 int write_object(int fd, void *o, int outputflags) {
753         uint8_t bytes[256];
754         char serialized[512];
755         size_t outlen;
756         int type;
757         union signobject *obj = o;
758
759         type = ((struct secret_key *)obj)->type;
760
761         if (outputflags & RAW) {
762                 switch (type) {
763                         case 0x01: hex(serialized, obj->sk.key, 32);
764                                    outlen = 64;
765                                    break;
766                         case 0x02: hex(serialized, obj->pk.key, 32);
767                                    outlen = 64;
768                                    break;
769                         case 0x03: hex(serialized, obj->sig.signature, 64);
770                                    outlen = 128;
771                                    break;
772                         default:
773                                    return 0;
774                 }
775         } else {
776                 outlen = 512;
777                 switch (type) {
778                         case 0x01: seckey_bytea(bytes, &obj->sk); break;
779                         case 0x02: pubkey_bytea(bytes, &obj->pk); break;
780                         case 0x03: signature_bytea(bytes, &obj->sig); break;
781                         memset(bytes, 0, sizeof bytes);
782                         default: return 0;
783                 }
784                 serialize(serialized, bytes);
785         }
786
787         write(fd, serialized, outlen);
788         memset(serialized, 0, outlen);
789
790         return 1;
791 }
792
793 /* TODO work on strings, not file output */
794 void write_to_512(int fd, int output) {
795         char trailer[65];
796         memset(trailer, '-', 64);
797         trailer[64] = '\n';
798
799         while (output < 512) {
800                 int shortfall = 512 - output;
801                 if (shortfall >= 65) {
802                         write(fd, trailer, 65);
803                         output += 65;
804                         continue;
805                 }
806                 write(fd, trailer + (65-shortfall), shortfall);
807                 output += shortfall;
808         }
809 }
810
811 int dump_signature(int fd, struct signature *sig) {
812         char as_str[1024], key[64], sigstr[128];
813         int output;
814         int64_t curtime = time(0);
815
816         hex(key, sig->key, 32);
817         hex(sigstr, sig->signature, 64);
818
819         output = sprintf(as_str, "Type: %s\nSigned: %ld\n%s: %ld\nPublic Key: %s\nSignature:\n%.64s\n%.64s\n",
820                         "signature",
821                         sig->signtime,
822                         curtime > sig->expires ? "Expired" : "Expires",
823                         sig->expires, key,
824                         sigstr, sigstr+64);
825         write(fd, as_str, strlen(as_str));
826         write_to_512(fd, output);
827
828         return 1;
829 }
830
831 int dump_public_key(int fd, struct public_key *pk) {
832         char as_str[1024], key[64], sig[128];
833         int output;
834         int64_t curtime = time(0);
835
836         hex(key, pk->key, 32);
837         hex(sig, pk->signature, 64);
838
839         output = sprintf(as_str, "Type: %s\nId: \"%s\"\nCreated: %ld\n%s: %ld\nKey: %.64s\nSignature:\n%.64s\n%.64s\n",
840                         "public key",
841                         pk->id, pk->created,
842                         curtime > pk->expires ? "Expired" : "Expires",
843                         pk->expires, key,
844                         sig, sig+64);
845         write(fd, as_str, strlen(as_str));
846         write_to_512(fd, output);
847
848         return 1;
849 }
850
851 int dump_secret_key(int fd, struct secret_key *sk) {
852         char as_str[1024];
853         char key[64];
854         int output;
855         int64_t curtime = time(0);
856         char exprep[64];
857
858         hex(key, sk->key, 32);
859         if (sk->expires == INT64_MAX) {
860                 sprintf(exprep, "never");
861         } else {
862                 sprintf(exprep, "%ld", sk->expires);
863         }
864
865         output = sprintf(as_str, "Type: %s\nEncrypted: %s\nId: \"%s\"\nCreated: %ld\n%s: %s\nKey: %.64s\n",
866                         "secret key",
867                         sk->encryption ? "yes" : "no",
868                         sk->id, sk->created,
869                         curtime > sk->expires ? "Expired" : "Expires",
870                         exprep, key);
871         write(fd, as_str, strlen(as_str));
872         write_to_512(fd, output);
873
874         return 1;
875 }
876
877 int dump_object(int fd, void *obj) {
878         int rv;
879         switch (((struct secret_key *)obj)->type) {
880                 case 0x01: rv = dump_secret_key(fd, obj); break;
881                 case 0x02: rv = dump_public_key(fd, obj); break;
882                 case 0x03: rv = dump_signature(fd, obj); break;
883                 default: rv = 0; break;
884         }
885         return rv;
886 }
887
888 /* returns a malloced keyfile name.  no check is made to see if the
889  * file actually exists
890  */
891 char *find_keyfile(char *file) {
892         char *f = 0;
893
894         if (file) {
895                 f = strdup(file);
896         } else if (getenv("ZPM_KEYFILE")) {
897                 f = strdup(getenv("ZPM_KEYFILE"));
898         } else {
899                 char *home = getenv("HOME");
900                 if (home) {
901                         size_t need;
902                         need = snprintf(0, 0, "%s/.zpm/key", home);
903                         char *freefile = malloc(need + 1);
904                         if (freefile) {
905                                 snprintf(freefile, need+1, "%s/.zpm/key", home);
906                         }
907                         f = freefile;
908                 }
909         }
910
911         return f;
912 }
913
914 int obj_id_match(union signobject *obj, char *id) {
915         if (!obj || !id) {
916                 return 1;
917         }
918
919         switch(object_type(obj)) {
920                 case SECRET_KEY:
921                         return !strcmp(obj->sk.id, id);
922                         break;
923                 case PUBLIC_KEY:
924                         return !strcmp(obj->pk.id, id);
925                         break;
926                 default:
927                         return 1;
928                         break;
929         }
930
931         return 1;
932 }
933
934 int key_id_match(struct secret_key *sk, char *id) {
935         if (!sk && !id) {
936                 return 1;
937         }
938         /* TODO look for substring */
939         return !strcmp(sk->id, id);
940 }
941
942 /* try to populate a secret key structure.
943  * preference order:
944  * direct specified string, won't have any additional info added
945  * string from ZPM_KEY
946  * file, if id, try to match
947  * file from ZPM_KEYFILE
948  * file at ~/.zpm/key
949  * otherwise fail
950  * if direct from string, encrypted?  assume no.  need option then.
951  */
952
953 /* can probably just call read_item */
954 int read_object(int fd, union signobject *obj) {
955         char buf[512];
956         ssize_t bytes;
957         
958         bytes = read512(fd, buf);
959         if (bytes < 512) {
960                 return 0;
961         }
962
963         return deserialize(obj, buf, bytes);
964 }
965
966 int find_secret_key(struct secret_key *sk, char *id, char *file, char *direct) {
967         char *path = 0;
968         int fd, bytes;
969         size_t len;
970
971         if (direct || (direct = getenv("ZPM_KEY"))) {
972                 /* TODO check strlen == 64 */
973                 len = strlen(direct);
974                 if (len < 2 * sizeof sk->key) {
975                         return 2;
976                 }
977                 memset(sk->key, 0, sizeof sk->key);
978                 bytes = hex2bin(sk->key, sizeof sk->key, direct, len);
979                 if (bytes != sizeof sk->key) {
980                         return 0;
981                 }
982                 create_key(sk, 0);
983                 return 1;
984         } else if (file) {
985                 path = find_keyfile(file);
986                 if (!path) {
987                         return 0;
988                 }
989
990                 fd = open(path, O_RDONLY);
991                 free(path);
992                 if (fd == -1) {
993                         return 0;
994                 }
995
996                 int64_t curtime = time(0);
997                 int type;
998                 do {
999                         type = read_object(fd, (union signobject *)sk);
1000                         if (type != SECRET_KEY) {
1001                                 continue;
1002                         }
1003                         if (curtime > sk->expires) {
1004                                 continue;
1005                         }
1006                         if (!id || key_id_match(sk, id)) {
1007                                 close(fd);
1008                                 return 1;
1009                         }
1010                 } while (type != 0);
1011                 close(fd);
1012         }
1013
1014         return 0;
1015 }
1016
1017 int open_output(char *path) {
1018         int fd = 1;
1019
1020         if (path && strcmp(path, "-") != 0) {
1021                 fd = open(path, O_WRONLY|O_CREAT, 0600);
1022         }
1023
1024         return fd;
1025 }
1026
1027 void set_key_id(struct secret_key *sk, char *id) {
1028         memset(sk->id, 0, 120);
1029         if (id) {
1030                 strncpy(sk->id, id, 119);
1031         }
1032 }
1033
1034 void set_pub_id(struct public_key *sk, char *id) {
1035         memset(sk->id, 0, 120);
1036         if (id) {
1037                 strncpy(sk->id, id, 119);
1038         }
1039 }
1040
1041 int object_filter(union signobject *obj, int type, char *id, char *prefix) {
1042         int otype;
1043         size_t len;
1044
1045         otype = object_type(obj);
1046
1047         if (otype == 0) {
1048                 return 0;
1049         }
1050
1051         if (type && otype != type) {
1052                 return 0;
1053         }
1054
1055         if (otype != SECRET_KEY) {
1056                 return 0;
1057         }
1058
1059         if (id) {
1060                 /* TODO memmem */
1061                 if (!key_id_match(&obj->sk, id)) {
1062                         return 0;
1063                 }
1064         }
1065
1066         if (prefix) {
1067                 char buf[32];
1068                 len = strlen(prefix);
1069                 len = hex2bin(buf, sizeof buf, prefix, len);
1070                 if (memcmp(obj->sk.key, buf, len) != 0) {
1071                         return 0;
1072                 }
1073         }
1074
1075         return 1;
1076 }
1077
1078 /* read or construct a secret key */
1079 int find_key(struct secret_key *sk, struct signing_context *ctx) {
1080         char *keystring, *keyfile, *idstring, *keyprefix;
1081         size_t len;
1082
1083         keystring = ctx->keystring;
1084         keyfile = ctx->keyfile;
1085         idstring = ctx->keyid;
1086         keyprefix = ctx->keyprefix;
1087
1088         //fprintf(stderr, "looking for key, str = \"%s\", file = \"%s\", id = \"%s\", prefix = \"%s\"\n", keystring, keyfile, idstring, keyprefix);
1089
1090         if (keystring) {
1091                 len = strlen(keystring);
1092                 if (len < 64) {
1093                         return 0;
1094                 }
1095                 hex2bin(sk->key, sizeof sk->key, keystring, len);
1096                 create_key(sk, 0);
1097                 set_key_id(sk, idstring);
1098                 return 1;
1099         } else {
1100                 char *keyringfile = find_keyfile(keyfile);
1101                 if (!keyringfile) {
1102                         return 0;
1103                 }
1104                 int keyring = open(keyringfile, O_RDONLY);
1105                 union signobject obj;
1106                 int rv;
1107                 while ((rv = read_object(keyring, &obj))) {
1108                         if (rv != SECRET_KEY) {
1109                                 continue;
1110                         }
1111                         if (object_filter(&obj, SECRET_KEY, idstring, keyprefix)) {
1112                                 break;
1113                         }
1114                 }
1115                 close(keyring);
1116                 if (rv == 1) {
1117                         return 1;
1118                 }
1119         }
1120
1121         if (sk->encryption && ctx->passphrase) {
1122                 collect_key(ctx->passkey, ctx->passphrase);
1123                 decrypt_key(sk, ctx->passkey);
1124         }
1125
1126         return 0;
1127 }
1128
1129 /* flags: 1 = hex encoded, 2 = input is path */
1130 char *create_message(char *in, size_t *len, int flags) {
1131         char *msg = 0;
1132         if (in) {
1133                 if (flags == 2) {
1134                         msg = map(in, len);
1135                 } else if (flags == 1) {
1136                         *len = strlen(in);
1137                         msg = malloc(*len/2 + 2);
1138                         *len = hex2bin(msg, *len, in, *len);
1139                 } else {
1140                         *len = strlen(in);
1141                         msg = in;
1142                 }
1143         } else {
1144                 /* would need to read from stdin and buffer */
1145         }
1146
1147
1148         return msg;
1149 }
1150
1151 char *construct_message(char *ms, char *path, size_t *mlen, int flags) {
1152         char *msg = 0, *mapped = 0;
1153         *mlen = 0;
1154
1155         if (ms) {
1156                 *mlen = strlen(ms);
1157                 msg = ms;
1158         } else if (path) {
1159                 mapped = msg = map(path, mlen);
1160         }
1161
1162         if (flags) {
1163                 /* input is hex encoded */
1164                 char *new;
1165                 new = malloc(*mlen/2+1);
1166                 *mlen = hex2bin(new, *mlen/2+1, msg, *mlen);
1167                 msg = new;
1168         }
1169
1170         return msg;
1171 }
1172
1173         /* TODO should use mlock()ed memory for the secret key */
1174 #if 0
1175 #if _POSIX_ADVISORY_INFO > 0
1176         long pagesize = sysconf(_SC_PAGESIZE);
1177         int rv = posix_memalign(&sk, pagesize, sizeof *sk);
1178         if (rv) {
1179                 mlock(sk, sizeof sk);
1180                 /* not able to lock, use stack memory */
1181         } else {
1182                 /* not able to allocate, use stack memory */
1183         }
1184         /* TODO if the allocate or lock fails, try mlockall(),
1185          * if that fails, abort or perhaps continue if insecure mode */
1186         /* TODO also mlock buffers */
1187 #endif
1188 #endif
1189
1190 /* if flags == 0, then need to hash the message and the signature info
1191  * before verifying, otherwise, bare sign, so just verify
1192  */
1193 int verify(struct signature *sig, char *message, size_t mlen, int flags) {
1194         char hash[64];
1195
1196         if (flags == 0) {
1197                 sighash(hash, sig, message, mlen);
1198                 message = hash;
1199                 mlen = sizeof hash;
1200         }
1201
1202         return ed25519_verify(sig->signature, sig->key, message, mlen);
1203 }
1204
1205 int generate_key(struct secret_key *sk, char *keystring, char *idstring) {
1206         size_t len;
1207
1208         if (!sk) {
1209                 return 0;
1210         }
1211
1212         if (keystring) {
1213                 len = strlen(keystring);
1214                 if (len < 64) {
1215                         return 0;
1216                 }
1217                 hex2bin(sk->key, sizeof sk->key, keystring, len);
1218                 create_key(sk, 0);
1219         } else {
1220                 create_key(sk, 1);
1221         }
1222
1223         if (idstring) {
1224                 strncpy(sk->id, idstring, 119);
1225         }
1226
1227         return 1;
1228 }
1229
1230 int list_object(int fd, union signobject *obj) {
1231         if (fd >= 0 && obj) {
1232                 dump_object(fd, obj);
1233         }
1234         return 1;
1235 }
1236
1237 /* TODO can be just a find_key and take an arg */
1238 int find_public_key(struct public_key *pk, char *id, char *pstr, char *pfile) {
1239         char *path = 0, buf[32];
1240         int fd, bytes, type = 0;
1241         size_t len;
1242
1243         if (!pstr && !pfile) {
1244                 pstr = getenv("ZPM_PUBLIC_KEY");
1245         }
1246
1247         if (pstr) {
1248                 /* TODO check strlen == 64 */
1249                 len = strlen(pstr);
1250                 if (len >= 512) {
1251                         type = deserialize(pk, pstr, len);
1252                 } else if (len >= 64) {
1253                         bytes = hex2bin(buf, sizeof buf, pstr, len);
1254                         if (bytes == 32) {
1255                                 pubkey_init(pk);
1256                                 memcpy(pk->key, buf, 32);
1257                                 if (id) {
1258                                         set_pub_id(pk, id);
1259                                 }
1260                                 type = PUBLIC_KEY;
1261                         }
1262                 }
1263         } else if (pfile) {
1264                 path = find_keyfile(pfile);
1265                 if (!path) {
1266                         return 0;
1267                 }
1268
1269                 fd = open(path, O_RDONLY);
1270                 free(path);
1271                 if (fd == -1) {
1272                         return 0;
1273                 }
1274
1275                 int64_t curtime = time(0);
1276                 int type;
1277                 do {
1278                         type = read_object(fd, (union signobject *)pk);
1279                         if (type != PUBLIC_KEY) {
1280                                 continue;
1281                         }
1282                         if (curtime > pk->expires) {
1283                                 /* TODO warn? */
1284                                 continue;
1285                         }
1286                         if (!id || obj_id_match((union signobject *)pk, id)) {
1287                                 close(fd);
1288                                 return type;
1289                         }
1290                 } while (type != 0);
1291                 close(fd);
1292         }
1293
1294         return type;
1295 }
1296
1297 int find_signature(struct signature *sig, char *sigstring, char *sigfile) {
1298         size_t len;
1299         int type = 0;
1300         char *mapped = 0;
1301         char buf[64];
1302
1303         if (sigstring) {
1304                 len = strlen(sigstring);
1305                 if (len >= 512) {
1306                         type = deserialize(sig, sigstring, len);
1307                 } else if (len >= 128) {
1308                         len = hex2bin(buf, sizeof buf, sigstring, len);
1309                         if (len == 64) {
1310                                 init_signature(sig);
1311                                 memcpy(sig->signature, buf, 64);
1312                                 type = SIGNATURE;
1313                         }
1314                 }
1315         } else if (sigfile) {
1316                 mapped = map(sigfile, &len);
1317                 if (mapped && len >= 512) {
1318                         type = deserialize(sig, mapped, len);
1319                 }
1320         }
1321
1322         if (mapped) {
1323                 munmap(mapped, len);
1324         }
1325         return type;
1326 }
1327
1328 int object_match(union signobject *a, union signobject *b) {
1329         if (!a && !b) {
1330                 return 1;
1331         }
1332         if (!a || !b) {
1333                 return 0;
1334         }
1335
1336         if (object_type(a) != object_type(b)) {
1337                 return 0;
1338         }
1339
1340         if (object_type(a) == PUBLIC_KEY) {
1341                 return memcmp(a->pk.key, b->pk.key, 32) == 0;
1342         } else if (object_type(a) == SECRET_KEY) {
1343                 return memcmp(a->sk.key, b->sk.key, 32) == 0;
1344         } else if (object_type(a) == SIGNATURE) {
1345                 if (memcmp(a->sig.key, b->sig.key, 32) != 0) {
1346                         return 0;
1347                 }
1348                 return memcmp(a->sig.signature, b->sig.signature, 64) == 0;
1349         }
1350
1351         return 0;
1352 }
1353
1354 /* return true if we find something that matches obj */
1355 int find_object(int fd, union signobject *lookfor) {
1356         union signobject obj;
1357         while (read_object(fd, &obj) > 0) {
1358                 if (object_match(lookfor, &obj)) {
1359                         return 1;
1360                 }
1361         }
1362
1363         return 0;
1364 }
1365 #include <sys/time.h>
1366 #include <sys/resource.h>
1367
1368 int main(int ac, char *av[]) {
1369         /*
1370          * M = message, P = public key, K = secret key, S = signature
1371          * T = timestamp, E = expires, I = identity, H = message hash
1372          * C = ciphertext, W = password
1373          */
1374         struct signing_context ctx = { 0 };
1375
1376         unsigned char *message = 0;
1377         size_t mlen;
1378         char *messagefile = 0;
1379         char *messagestring = 0;
1380
1381         char *timestring = 0, *expirestring = 0;
1382         int64_t timestamp = 0, expires = INT64_MAX;
1383
1384         char *passphrase = 0;
1385         unsigned char passkey[32];
1386
1387         char *keyid = 0, *keyprefix = 0;
1388         struct secret_key sk = { 0 };
1389         char *keyfile = 0, *keystring = 0;
1390
1391         struct public_key pk = { 0 };
1392         char *pubfile = 0, *pubstring = 0;
1393
1394         struct signature sig = { 0 };
1395         char *sigfile = 0, *sigstring = 0;
1396
1397         char *encfile = 0, *encstring = 0;
1398         char *outfile = 0;
1399         int output = 1; /* file descriptor */
1400
1401         int option, argn;
1402         int mode = 0;
1403
1404         int hexencoded = 0, outputflags = 0;
1405         int debug = 0, quiet = 0, bareinput = 0;
1406         int outputmsghash = 0;
1407         int rv;
1408
1409 #if 0
1410 #if _POSIX_ADVISORY_INFO > 0
1411         fprintf(stderr, "locking memory\n");
1412         struct rlimit lim;
1413         getrlimit(RLIMIT_MEMLOCK, &lim);
1414         fprintf(stderr, "memlock limit %llu/%llu\n", lim.rlim_cur, lim.rlim_max);
1415         struct public_key *pkp;
1416         posix_memalign(&pkp, 
1417         rv = mlockall(MCL_CURRENT|MCL_FUTURE); /* can't happen, have to just
1418                                                   lock sk and maybe ctx */
1419         if (rv == -1) {
1420                 perror("unable to lock memory");
1421         }
1422 #endif
1423 #endif
1424
1425         while ((option = getopt(ac, av, "vsgelxyirdHo:hbT:E:n:w:m:N:k:K:p:P:f:F:c:C:")) != -1) {
1426                 switch (option) {
1427                         /* modes */
1428                         case 'v': mode = VERIFY; break;
1429                         case 's': mode = SIGN; break;
1430                         case 'g': mode = KEYGEN; break;
1431                         case 'e': mode = EXTRACT; break;
1432                         case 'l': mode = LIST; break;
1433                         case 'x': mode = ENCRYPT; break;
1434                         case 'y': mode = DECRYPT; break;
1435                         case 'i': mode = IMPORT; break;
1436                                   /* more modes:
1437                                    * remove pw, add pw, export, delete
1438                                    * need a manage mode to delete
1439                                    * or update keys
1440                                    */
1441 #if 0
1442                         /* trust level */
1443                         case 't': trust = strtoul(optarg, 0, 10); break;
1444 #endif
1445                                   /* outputs */
1446                         case 'r': outputflags |= RAW; break;
1447                         case 'd': debug++; break;
1448                         case 'H': outputmsghash = 1; break;
1449                         case 'o': outfile = optarg; break;
1450                         case 'q': quiet++; break;
1451
1452                                   /* inputs */
1453                         case 'h': hexencoded = 1; break;
1454                         case 'b': bareinput = 1; break;
1455                         case 'T': timestring = optarg; break; /* T */
1456                         case 'E': expirestring = optarg; break; /* E */
1457                         case 'n': keyid = optarg; break; /* I */
1458                         case 'w': passphrase = optarg; break; /* W */
1459                         case 'm': messagestring = optarg; break; /* M */
1460                         case 'N': keyprefix = optarg; break; /* K ish */
1461                         case 'k': keyfile = optarg; break; /* K */
1462                         case 'K': keystring = optarg; break; /* K */
1463                         case 'p': pubfile = optarg; break; /* P */
1464                         case 'P': pubstring = optarg; break; /* P */
1465                         case 'f': sigfile = optarg; break; /* S */
1466                         case 'F': sigstring = optarg; break; /* S */
1467                         case 'c': encfile = optarg; break; /* C */
1468                         case 'C': encstring = optarg; break; /* C */
1469
1470                         default:
1471                                   exit(EXIT_FAILURE);
1472                                   break;
1473                 }
1474         }
1475
1476         argn = optind;
1477
1478         /*
1479          * M = message, P = public key, K = secret key, S = signature
1480          * T = timestamp, E = expires, I = identity, H = message hash
1481          * C = ciphertext, W = password
1482          *
1483          * -sb bare data sign (M, K) -> S
1484          * -s full data sign ( (M,T,E) -> H, K) -> S
1485          * -s key sign ( (P,T,E) -> H, K) -> S
1486          * -e extract (K) -> P
1487          * -g generate (T, E, I) -> K (default to keyring append)
1488          * -g generate (K, T, E, I) -> K (default to keyring append)
1489          *    self sign ( (K->P,T,E,I) -> H, M) -> S
1490          * import (K/P/S) -> keyring file append, stdout daft, unless redir
1491          * show (K/P/S) -> output input
1492          * -l list keys (K/P/S) -> key list, get from -k
1493          * -v verify (M, S) -> boolean, via exit value, no output
1494          * -x encrypt (M, K, T, E, P...) -> C
1495          * -y decrypt (C, K) -> M
1496          * -H generate signing hash for message or key
1497          *
1498          * output style: serialized, -d human readable, -r raw
1499          * input style: serialized, -b bare, -h hexencoded
1500          *
1501          * possible inputs: M K T E P I S C
1502          * M -> from -m, non-option arg, stdin
1503          * K -> from -K, ZPM_KEY, -k, ZPM_KEYFILE, ~/.zpm/key
1504          * P -> from -P, -p
1505          * S -> from -F, -f, second arg?
1506          * C -> from -C, -c, non-option arg, stdin
1507          * T -> from -T, time(NULL)
1508          * E -> from -E, never/-1
1509          * I -> from -n, ZPM_KEYID, K, S, null
1510          * W -> from -w, ZPM_PASS, ~/.zpm/pass, terminal
1511          */
1512
1513         if (timestring) {
1514                 timestamp = strtoull(timestring, 0, 10);
1515         } else {
1516                 timestamp = time(NULL);
1517         }
1518
1519         if (expirestring) {
1520                 expires = strtoull(expirestring, 0, 10);
1521         }
1522
1523         ctx.keystring = keystring;
1524         ctx.keyfile = keyfile;
1525         ctx.keyid = keyid;
1526         ctx.keyprefix = keyprefix;
1527         ctx.passphrase = passphrase;
1528
1529         if (mode == KEYGEN) {
1530                 rv = generate_key(&sk, keystring, keyid);
1531                 if (!rv) {
1532                         exit(EXIT_FAILURE);
1533                 }
1534                 sk.created = timestamp;
1535                 sk.expires = expires;
1536         } else if (mode == SIGN) {
1537                 char *firstarg = av[argn];
1538                 rv = find_key(&sk, &ctx);
1539                 if (!rv) {
1540                         fprintf(stderr, "unable to find signing key\n");
1541                         exit(EXIT_FAILURE);
1542                 }
1543                 char *message = construct_message(messagestring, firstarg, &mlen, hexencoded);
1544                 // dump_secret_key(2, &sk);
1545                 sig.signtime = timestamp;
1546                 sig.expires = expires;
1547                 rv = create_signature(&sig, &sk, bareinput, message, mlen);
1548                 if (!rv) {
1549                         exit(EXIT_FAILURE);
1550                 }
1551                 // dump_signature(2, &sig);
1552         } else if (mode == SIGNKEY) {
1553                 find_key(&sk, &ctx);
1554                 find_public_key(&pk, keyid, pubstring, pubfile);
1555                 /* TODO construct a message out of a public key */
1556                 mlen = 0;
1557                 sig.signtime = timestamp;
1558                 sig.expires = expires;
1559                 rv = create_signature(&sig, &sk, 0, message, mlen);
1560                 if (!rv) {
1561                         exit(EXIT_FAILURE);
1562                 }
1563         } else if (mode == EXTRACT) {
1564                 rv = find_key(&sk, &ctx);
1565                 if (passphrase) {
1566                         decrypt_sk(&sk, passphrase);
1567                 }
1568                 if (!rv) {
1569                         exit(EXIT_FAILURE);
1570                 }
1571                 derive_pubkey(&pk, &sk);
1572         } else if (mode == VERIFY) {
1573                 rv = find_signature(&sig, sigstring, sigfile);
1574                 if (rv == SIGNATURE) {
1575                         /* if you've specified the public key in a verify op,
1576                          * you probably know what you're doing
1577                          */
1578                         if (pubstring || pubfile) {
1579                                 rv = find_public_key(&pk, keyid, pubstring, pubfile);
1580                                 if (rv == PUBLIC_KEY) {
1581                                         memcpy(sig.key, pk.key, 32);
1582                                 }
1583                         }
1584                         //dump_signature(2, &sig);
1585
1586                         message = construct_message(messagestring, av[argn], &mlen, hexencoded);
1587                         rv = verify(&sig, message, mlen, bareinput);
1588                 } else {
1589                         rv = 0;
1590                 }
1591         } else if (mode == LIST) {
1592                 union signobject obj;
1593                 char *keyringfile = find_keyfile(keyfile);
1594                 if (!keyringfile) {
1595                         fprintf(stderr, "can't find keyring file\n");
1596                         exit(1);
1597                 }
1598                 int keyring = open(keyringfile, O_RDWR|O_APPEND);
1599                 if (keyring == -1) {
1600                         fprintf(stderr, "can't open keyring file %s\n", keyringfile);
1601                         perror("");
1602                         exit(EXIT_FAILURE);
1603                 }
1604                 while ((rv = read_object(keyring, &obj))) {
1605                         list_object(output, &obj);
1606                 }
1607                 close(keyring);
1608         } else if (mode == IMPORT) {
1609                 int fd, i, rv;
1610                 union signobject obj;
1611                 char *keyringfile = find_keyfile(keyfile);
1612                 int keyring = open(keyringfile, O_RDWR|O_APPEND);
1613                 if (keyring == -1) {
1614                         fprintf(stderr, "%s ", keyringfile);
1615                         perror("");
1616                         exit(EXIT_FAILURE);
1617                 }
1618                 for (i = argn; i < ac; i++) {
1619                         fd = open(av[i], O_RDONLY);
1620                         if (fd == -1) {
1621                                 fprintf(stderr, "%s ", av[i]);
1622                                 perror("");
1623                                 rv = 0;
1624                                 close(keyring);
1625                                 exit(EXIT_FAILURE);
1626                         }
1627                         while ((rv = read_object(fd, &obj))) {
1628                                 fprintf(stderr, "importing type %d\n", object_type(&obj));
1629                                 /* TODO probably a more efficient way to do
1630                                  * this.  Perhaps read in the keyring to
1631                                  * memory. */
1632                                 lseek(keyring, 0, SEEK_SET);
1633                                 if (!find_object(keyring, &obj)) {
1634                                         write_object(keyring, &obj, outputflags);
1635                                 }
1636                         }
1637                         close(fd);
1638                 }
1639                 close(keyring);
1640         } else if (mode == ENCRYPT) {
1641                 fprintf(stderr, "encryption not supported\n");
1642                 exit(EXIT_FAILURE);
1643         } else if (mode == DECRYPT) {
1644                 fprintf(stderr, "decryption not supported\n");
1645                 exit(EXIT_FAILURE);
1646         }
1647
1648         /*
1649          * now, do the action
1650          */
1651
1652         if (mode == KEYGEN) {
1653                 if (!outfile) {
1654                         outfile = find_keyfile(keyfile);
1655                 }
1656                 if (outfile && strcmp(outfile, "-") != 0) {
1657                         output = open(outfile, O_RDWR|O_CREAT|O_APPEND, 0600);
1658                 }
1659                 /* TODO encrypt key */
1660                 if (passphrase) {
1661                         fprintf(stderr, "encrypting key\n");
1662                         collect_key(passkey, passphrase);
1663                         encrypt_key(&sk, passkey);
1664                         //memset(passphrase, 0, strlen(passphrase));
1665                         memset(passkey, 0, 32);
1666                 }
1667                 // dump_secret_key(2, &sk);
1668                 write_secret_key(output, &sk, outputflags);
1669         } else if (mode == SIGN || mode == SIGNKEY) {
1670                 if (outfile && strcmp(outfile, "-") != 0) {
1671                         output = open(outfile, O_RDWR|O_CREAT|O_APPEND, 0600);
1672                 }
1673                 //dump_signature(2, &sig);
1674                 write_signature(output, &sig, outputflags);
1675         } else if (mode == EXTRACT) {
1676                 if (outfile && strcmp(outfile, "-") != 0) {
1677                         output = open(outfile, O_RDWR|O_CREAT|O_APPEND, 0600);
1678                 }
1679                 // dump_public_key(2, &pk);
1680                 write_public_key(output, &pk, outputflags);
1681         } else if (mode == VERIFY) {
1682                 exit(rv ? 0 : 1);
1683         } else if (mode == LIST) {
1684                 /* handled above */
1685         } else if (mode == IMPORT) {
1686                 /* handled above */
1687         } else if (mode == ENCRYPT) {
1688                 fprintf(stderr, "encryption not supported\n");
1689                 exit(EXIT_FAILURE);
1690         } else if (mode == DECRYPT) {
1691                 fprintf(stderr, "decryption not supported\n");
1692                 exit(EXIT_FAILURE);
1693         }
1694
1695         if (message && messagefile) {
1696                 munmap(message, mlen);
1697         }
1698
1699         memset(sk.key, 0, sizeof sk.key);
1700         return 0;
1701 }