1 /*-
2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Alistair Crooks (agc@NetBSD.org)
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29 #include "config.h"
30
31 #ifdef HAVE_SYS_CDEFS_H
32 #include <sys/cdefs.h>
33 #endif
34
35 #if defined(__NetBSD__)
36 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
37 __RCSID("$NetBSD: netpgp.c,v 1.106 2022/08/27 08:58:32 rillig Exp $");
38 #endif
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #include <sys/mman.h>
44
45 #ifdef HAVE_SYS_RESOURCE_H
46 #include <sys/resource.h>
47 #endif
48
49 #ifdef HAVE_FCNTL_H
50 #include <fcntl.h>
51 #endif
52
53 #include <errno.h>
54 #include <regex.h>
55 #include <stdarg.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <time.h>
59
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63
64 #include <errno.h>
65
66 #ifdef HAVE_LIMITS_H
67 #include <limits.h>
68 #endif
69
70 #include <netpgp.h>
71
72 #include "packet.h"
73 #include "packet-parse.h"
74 #include "keyring.h"
75 #include "errors.h"
76 #include "packet-show.h"
77 #include "create.h"
78 #include "netpgpsdk.h"
79 #include "memory.h"
80 #include "validate.h"
81 #include "readerwriter.h"
82 #include "netpgpdefs.h"
83 #include "crypto.h"
84 #include "ssh2pgp.h"
85 #include "defs.h"
86
87 /* read any gpg config file */
88 static int
conffile(netpgp_t * netpgp,char * homedir,char * userid,size_t length)89 conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length)
90 {
91 regmatch_t matchv[10];
92 regex_t keyre;
93 char buf[BUFSIZ];
94 FILE *fp;
95
96 __PGP_USED(netpgp);
97 (void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir);
98 if ((fp = fopen(buf, "r")) == NULL) {
99 return 0;
100 }
101 (void) memset(&keyre, 0x0, sizeof(keyre));
102 (void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)",
103 REG_EXTENDED);
104 while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
105 if (regexec(&keyre, buf, 10, matchv, 0) == 0) {
106 (void) memcpy(userid, &buf[(int)matchv[1].rm_so],
107 MIN((unsigned)(matchv[1].rm_eo -
108 matchv[1].rm_so), length));
109 if (netpgp->passfp == NULL) {
110 (void) fprintf(stderr,
111 "netpgp: default key set to \"%.*s\"\n",
112 (int)(matchv[1].rm_eo - matchv[1].rm_so),
113 &buf[(int)matchv[1].rm_so]);
114 }
115 }
116 }
117 (void) fclose(fp);
118 regfree(&keyre);
119 return 1;
120 }
121
122 /* small function to pretty print an 8-character raw userid */
123 static char *
userid_to_id(const uint8_t * userid,char * id)124 userid_to_id(const uint8_t *userid, char *id)
125 {
126 static const char *hexes = "0123456789abcdef";
127 int i;
128
129 for (i = 0; i < 8 ; i++) {
130 id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
131 id[(i * 2) + 1] = hexes[userid[i] & 0xf];
132 }
133 id[8 * 2] = 0x0;
134 return id;
135 }
136
137 /* print out the successful signature information */
138 static void
resultp(pgp_io_t * io,const char * f,pgp_validation_t * res,pgp_keyring_t * ring)139 resultp(pgp_io_t *io,
140 const char *f,
141 pgp_validation_t *res,
142 pgp_keyring_t *ring)
143 {
144 const pgp_key_t *key;
145 pgp_pubkey_t *sigkey;
146 unsigned from;
147 unsigned i;
148 time_t t;
149 char id[MAX_ID_LENGTH + 1];
150
151 for (i = 0; i < res->validc; i++) {
152 (void) fprintf(io->res,
153 "Good signature for %s made %s",
154 (f) ? f : "<stdin>",
155 ctime(&res->valid_sigs[i].birthtime));
156 if (res->duration > 0) {
157 t = res->birthtime + res->duration;
158 (void) fprintf(io->res, "Valid until %s", ctime(&t));
159 }
160 (void) fprintf(io->res,
161 "using %s key %s\n",
162 pgp_show_pka(res->valid_sigs[i].key_alg),
163 userid_to_id(res->valid_sigs[i].signer_id, id));
164 from = 0;
165 key = pgp_getkeybyid(io, ring,
166 (const uint8_t *) res->valid_sigs[i].signer_id,
167 &from, &sigkey);
168 if (sigkey == &key->enckey) {
169 (void) fprintf(io->res,
170 "WARNING: signature for %s made with encryption key\n",
171 (f) ? f : "<stdin>");
172 }
173 pgp_print_keydata(io, ring, key, "signature ", &key->key.pubkey, 0);
174 }
175 }
176
177 /* check there's enough space in the arrays */
178 static int
size_arrays(netpgp_t * netpgp,unsigned needed)179 size_arrays(netpgp_t *netpgp, unsigned needed)
180 {
181 char **temp;
182
183 if (netpgp->size == 0) {
184 /* only get here first time around */
185 netpgp->size = needed;
186 if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
187 (void) fprintf(stderr, "size_arrays: bad alloc\n");
188 return 0;
189 }
190 if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
191 free(netpgp->name);
192 (void) fprintf(stderr, "size_arrays: bad alloc\n");
193 return 0;
194 }
195 } else if (netpgp->c == netpgp->size) {
196 /* only uses 'needed' when filled array */
197 netpgp->size += needed;
198 temp = realloc(netpgp->name, sizeof(char *) * needed);
199 if (temp == NULL) {
200 (void) fprintf(stderr, "size_arrays: bad alloc\n");
201 return 0;
202 }
203 netpgp->name = temp;
204 temp = realloc(netpgp->value, sizeof(char *) * needed);
205 if (temp == NULL) {
206 (void) fprintf(stderr, "size_arrays: bad alloc\n");
207 return 0;
208 }
209 netpgp->value = temp;
210 }
211 return 1;
212 }
213
214 /* find the name in the array */
215 static int
findvar(netpgp_t * netpgp,const char * name)216 findvar(netpgp_t *netpgp, const char *name)
217 {
218 unsigned i;
219
220 for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
221 }
222 return (i == netpgp->c) ? -1 : (int)i;
223 }
224
225 /* append a key to a keyring */
226 static int
appendkey(pgp_io_t * io,pgp_key_t * key,char * ringfile)227 appendkey(pgp_io_t *io, pgp_key_t *key, char *ringfile)
228 {
229 pgp_output_t *create;
230 const unsigned noarmor = 0;
231 int fd;
232
233 if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
234 fd = pgp_setup_file_write(&create, ringfile, 0);
235 }
236 if (fd < 0) {
237 (void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
238 return 0;
239 }
240 if (!pgp_write_xfer_pubkey(create, key, noarmor)) {
241 (void) fprintf(io->errs, "Cannot write pubkey\n");
242 return 0;
243 }
244 pgp_teardown_file_write(create, fd);
245 return 1;
246 }
247
248 /* return filename of a keyring */
249 static char *
keyringfile(netpgp_t * netpgp,const char * name)250 keyringfile(netpgp_t *netpgp, const char *name)
251 {
252 char f[MAXPATHLEN];
253 char *homedir;
254 char *filename;
255
256 homedir = netpgp_getvar(netpgp, "homedir");
257 filename = netpgp_getvar(netpgp, name);
258 if (filename == NULL || filename[0] == '\0') {
259 (void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
260 filename = f;
261 }
262
263 return netpgp_strdup(filename);
264 }
265
266 /* return an empty keyring */
267 static void *
newkeyring(netpgp_t * netpgp,const char * name)268 newkeyring(netpgp_t *netpgp, const char *name)
269 {
270 pgp_keyring_t *keyring;
271 char *filename;
272
273 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
274 (void) fprintf(stderr, "newkeyring: bad alloc\n");
275 return NULL;
276 }
277
278 filename = keyringfile(netpgp, name);
279 netpgp_setvar(netpgp, name, filename);
280 free(filename);
281
282 return keyring;
283 }
284
285 /* read a keyring and return it */
286 static void *
readkeyring(netpgp_t * netpgp,const char * name)287 readkeyring(netpgp_t *netpgp, const char *name)
288 {
289 pgp_keyring_t *keyring;
290 const unsigned noarmor = 0;
291 char *filename;
292
293 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
294 (void) fprintf(stderr, "readkeyring: bad alloc\n");
295 return NULL;
296 }
297
298 filename = keyringfile(netpgp, name);
299 if (!pgp_keyring_fileread(keyring, noarmor, filename)) {
300 (void) fprintf(stderr, "Can't read %s %s\n", name, filename);
301 free(filename);
302 free(keyring);
303 return NULL;
304 }
305 netpgp_setvar(netpgp, name, filename);
306 free(filename);
307
308 return keyring;
309 }
310
311 /* write a keyring */
312 static int
writekeyring(netpgp_t * netpgp,const char * name,pgp_keyring_t * keyring,uint8_t * passphrase)313 writekeyring(netpgp_t *netpgp, const char *name, pgp_keyring_t *keyring, uint8_t *passphrase)
314 {
315 const unsigned noarmor = 0;
316 char *filename;
317
318 filename = keyringfile(netpgp, name);
319 if (!pgp_keyring_filewrite(keyring, noarmor, filename, passphrase)) {
320 (void) fprintf(stderr, "Can't write %s %s\n", name, filename);
321 free(filename);
322 return 0;
323 }
324 netpgp_setvar(netpgp, name, filename);
325 free(filename);
326
327 return 1;
328 }
329
330 /* append key to a keyring */
331 static int
appendtokeyring(netpgp_t * netpgp,const char * name,pgp_key_t * key)332 appendtokeyring(netpgp_t *netpgp, const char *name, pgp_key_t *key)
333 {
334 char *filename;
335 int ret;
336
337 filename = keyringfile(netpgp, name);
338 ret = appendkey(netpgp->io, key, filename);
339 free(filename);
340
341 return ret;
342 }
343
344 /* read keys from ssh key files */
345 static int
readsshkeys(netpgp_t * netpgp,char * homedir,const char * needseckey)346 readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey)
347 {
348 pgp_keyring_t *pubring;
349 pgp_keyring_t *secring;
350 struct stat st;
351 unsigned hashtype;
352 char *hash;
353 char f[MAXPATHLEN];
354 char *filename;
355
356 if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) {
357 /* set reasonable default for RSA key */
358 (void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir);
359 filename = f;
360 } else if (strcmp(&filename[strlen(filename) - 4], ".pub") != 0) {
361 /* got ssh keys, check for pub file name */
362 (void) snprintf(f, sizeof(f), "%s.pub", filename);
363 filename = f;
364 }
365 /* check the pub file exists */
366 if (stat(filename, &st) != 0) {
367 (void) fprintf(stderr, "readsshkeys: bad pubkey filename '%s'\n", filename);
368 return 0;
369 }
370 if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
371 (void) fprintf(stderr, "readsshkeys: bad alloc\n");
372 return 0;
373 }
374 /* openssh2 keys use md5 by default */
375 hashtype = PGP_HASH_MD5;
376 if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) {
377 /* openssh 2 hasn't really caught up to anything else yet */
378 if (netpgp_strcasecmp(hash, "md5") == 0) {
379 hashtype = PGP_HASH_MD5;
380 } else if (netpgp_strcasecmp(hash, "sha1") == 0) {
381 hashtype = PGP_HASH_SHA1;
382 } else if (netpgp_strcasecmp(hash, "sha256") == 0) {
383 hashtype = PGP_HASH_SHA256;
384 }
385 }
386 if (!pgp_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) {
387 free(pubring);
388 (void) fprintf(stderr, "readsshkeys: can't read %s\n",
389 filename);
390 return 0;
391 }
392 if (netpgp->pubring == NULL) {
393 netpgp->pubring = pubring;
394 } else {
395 pgp_append_keyring(netpgp->pubring, pubring);
396 }
397 if (needseckey) {
398 netpgp_setvar(netpgp, "sshpubfile", filename);
399 /* try to take the ".pub" off the end */
400 if (filename == f) {
401 f[strlen(f) - 4] = 0x0;
402 } else {
403 (void) snprintf(f, sizeof(f), "%.*s",
404 (int)strlen(filename) - 4, filename);
405 filename = f;
406 }
407 if ((secring = calloc(1, sizeof(*secring))) == NULL) {
408 free(pubring);
409 (void) fprintf(stderr, "readsshkeys: bad alloc\n");
410 return 0;
411 }
412 if (!pgp_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) {
413 free(pubring);
414 free(secring);
415 (void) fprintf(stderr, "readsshkeys: can't read sec %s\n", filename);
416 return 0;
417 }
418 netpgp->secring = secring;
419 netpgp_setvar(netpgp, "sshsecfile", filename);
420 }
421 return 1;
422 }
423
424 /* get the uid of the first key in the keyring */
425 static int
get_first_ring(pgp_keyring_t * ring,char * id,size_t len,int last)426 get_first_ring(pgp_keyring_t *ring, char *id, size_t len, int last)
427 {
428 uint8_t *src;
429 int i;
430 int n;
431
432 if (ring == NULL || ring->keyc == 0) {
433 return 0;
434 }
435 (void) memset(id, 0x0, len);
436 src = ring->keys[(last) ? ring->keyc - 1 : 0].sigid;
437 for (i = 0, n = 0 ; i < PGP_KEY_ID_SIZE ; i += 2) {
438 n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]);
439 }
440 id[n] = 0x0;
441 return 1;
442 }
443
444 /* find the time - in a specific %Y-%m-%d format - using a regexp */
445 static int
grabdate(char * s,int64_t * t)446 grabdate(char *s, int64_t *t)
447 {
448 static regex_t r;
449 static int compiled;
450 regmatch_t matches[10];
451 struct tm tm;
452
453 if (!compiled) {
454 compiled = 1;
455 (void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED);
456 }
457 if (regexec(&r, s, 10, matches, 0) == 0) {
458 (void) memset(&tm, 0x0, sizeof(tm));
459 tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10);
460 tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1;
461 tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10);
462 *t = mktime(&tm);
463 return 1;
464 }
465 return 0;
466 }
467
468 /* get expiration in seconds */
469 static uint64_t
get_duration(char * s)470 get_duration(char *s)
471 {
472 uint64_t now;
473 int64_t t;
474 const char *mult;
475
476 if (s == NULL) {
477 return 0;
478 }
479 now = (uint64_t)strtoull(s, NULL, 10);
480 if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) {
481 switch(*mult) {
482 case 'h':
483 return now * 60 * 60;
484 case 'd':
485 return now * 60 * 60 * 24;
486 case 'w':
487 return now * 60 * 60 * 24 * 7;
488 case 'm':
489 return now * 60 * 60 * 24 * 31;
490 case 'y':
491 return now * 60 * 60 * 24 * 365;
492 }
493 }
494 if (grabdate(s, &t)) {
495 return t;
496 }
497 return (uint64_t)strtoll(s, NULL, 10);
498 }
499
500 /* get birthtime in seconds */
501 static int64_t
get_birthtime(char * s)502 get_birthtime(char *s)
503 {
504 int64_t t;
505
506 if (s == NULL) {
507 return time(NULL);
508 }
509 if (grabdate(s, &t)) {
510 return t;
511 }
512 return (uint64_t)strtoll(s, NULL, 10);
513 }
514
515 /* resolve the userid */
516 static const pgp_key_t *
resolve_userid(netpgp_t * netpgp,const pgp_keyring_t * keyring,const char * userid)517 resolve_userid(netpgp_t *netpgp, const pgp_keyring_t *keyring, const char *userid)
518 {
519 const pgp_key_t *key;
520 pgp_io_t *io;
521
522 if (userid == NULL) {
523 userid = netpgp_getvar(netpgp, "userid");
524 if (userid == NULL)
525 return NULL;
526 } else if (userid[0] == '0' && userid[1] == 'x') {
527 userid += 2;
528 }
529 io = netpgp->io;
530 if ((key = pgp_getkeybyname(io, keyring, userid)) == NULL) {
531 (void) fprintf(io->errs, "Can't find key '%s'\n", userid);
532 }
533 return key;
534 }
535
536 /* return 1 if the file contains ascii-armoured text */
537 static unsigned
isarmoured(pgp_io_t * io,const char * f,const void * memory,const char * text)538 isarmoured(pgp_io_t *io, const char *f, const void *memory, const char *text)
539 {
540 regmatch_t matches[10];
541 unsigned armoured;
542 regex_t r;
543 FILE *fp;
544 char buf[BUFSIZ];
545
546 armoured = 0;
547 (void) regcomp(&r, text, REG_EXTENDED);
548 if (f) {
549 if ((fp = fopen(f, "r")) == NULL) {
550 (void) fprintf(io->errs, "isarmoured: can't open '%s'\n", f);
551 regfree(&r);
552 return 0;
553 }
554 if (fgets(buf, (int)sizeof(buf), fp) != NULL) {
555 if (regexec(&r, buf, 10, matches, 0) == 0) {
556 armoured = 1;
557 }
558 }
559 (void) fclose(fp);
560 } else {
561 if (regexec(&r, memory, 10, matches, 0) == 0) {
562 armoured = 1;
563 }
564 }
565 regfree(&r);
566 return armoured;
567 }
568
569 /* vararg print function */
570 static void
p(FILE * fp,const char * s,...)571 p(FILE *fp, const char *s, ...)
572 {
573 va_list args;
574
575 va_start(args, s);
576 while (s != NULL) {
577 (void) fprintf(fp, "%s", s);
578 s = va_arg(args, char *);
579 }
580 va_end(args);
581 }
582
583 /* print a JSON object to the FILE stream */
584 static void
pobj(FILE * fp,mj_t * obj,int depth)585 pobj(FILE *fp, mj_t *obj, int depth)
586 {
587
588 if (obj == NULL) {
589 (void) fprintf(stderr, "No object found\n");
590 return;
591 }
592
593 mj_pretty(obj, fp, depth, "");
594 }
595
596 /* return the time as a string */
597 static char *
ptimestr(char * dest,size_t size,time_t t)598 ptimestr(char *dest, size_t size, time_t t)
599 {
600 struct tm *tm;
601
602 tm = gmtime(&t);
603 (void) snprintf(dest, size, "%04d-%02d-%02d",
604 tm->tm_year + 1900,
605 tm->tm_mon + 1,
606 tm->tm_mday);
607 return dest;
608 }
609
610 /* format a JSON object */
611 static void
format_json_key(FILE * fp,mj_t * obj,const int psigs)612 format_json_key(FILE *fp, mj_t *obj, const int psigs)
613 {
614 int64_t birthtime;
615 int64_t duration;
616 time_t now;
617 char tbuf[32];
618 char *s;
619 mj_t *sub;
620 int i;
621
622 if (pgp_get_debug_level(__FILE__)) {
623 mj_asprint(&s, obj, MJ_HUMAN);
624 (void) fprintf(stderr, "formatobj: json is '%s'\n", s);
625 free(s);
626 }
627 if (obj->c == 2 && obj->value.v[1].type == MJ_STRING &&
628 strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) {
629 /* whole key has been rovoked - just return */
630 return;
631 }
632 pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0);
633 p(fp, " ", NULL);
634 pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0);
635 p(fp, "/", NULL);
636 pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0);
637 p(fp, " ", NULL);
638 pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0);
639 birthtime = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10);
640 p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL);
641 duration = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10);
642 if (duration > 0) {
643 now = time(NULL);
644 p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ",
645 ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL);
646 }
647 p(fp, "\n", "Key fingerprint: ", NULL);
648 pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0);
649 p(fp, "\n", NULL);
650 /* go to field after \"duration\" */
651 for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) {
652 if (strcmp(obj->value.v[i].value.s, "uid") == 0) {
653 sub = &obj->value.v[i + 1];
654 p(fp, "uid", NULL);
655 pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */
656 pobj(fp, &sub->value.v[1], 1); /* any revocation */
657 p(fp, "\n", NULL);
658 } else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) {
659 sub = &obj->value.v[i + 1];
660 p(fp, "encryption", NULL);
661 pobj(fp, &sub->value.v[0], 1); /* size */
662 p(fp, "/", NULL);
663 pobj(fp, &sub->value.v[1], 0); /* alg */
664 p(fp, " ", NULL);
665 pobj(fp, &sub->value.v[2], 0); /* id */
666 p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
667 (time_t)strtoll(sub->value.v[3].value.s, NULL, 10)),
668 "\n", NULL);
669 } else if (strcmp(obj->value.v[i].value.s, "sig") == 0) {
670 sub = &obj->value.v[i + 1];
671 p(fp, "sig", NULL);
672 pobj(fp, &sub->value.v[0], 8); /* size */
673 p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
674 (time_t)strtoll(sub->value.v[1].value.s, NULL, 10)),
675 " ", NULL); /* time */
676 pobj(fp, &sub->value.v[2], 0); /* human name */
677 p(fp, "\n", NULL);
678 } else {
679 fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s);
680 pobj(fp, &obj->value.v[i], 0); /* human name */
681 }
682 }
683 p(fp, "\n", NULL);
684 }
685
686 /* save a pgp pubkey to a temp file */
687 static int
savepubkey(char * res,char * f,size_t size)688 savepubkey(char *res, char *f, size_t size)
689 {
690 size_t len;
691 int cc;
692 int wc;
693 int fd;
694
695 (void) snprintf(f, size, "/tmp/pgp2ssh.XXXXXXX");
696 if ((fd = mkstemp(f)) < 0) {
697 (void) fprintf(stderr, "can't create temp file '%s'\n", f);
698 return 0;
699 }
700 len = strlen(res);
701 for (cc = 0 ; (wc = (int)write(fd, &res[cc], len - (size_t)cc)) > 0 ; cc += wc) {
702 }
703 (void) close(fd);
704 return 1;
705 }
706
707 /* format a uint32_t */
708 static int
formatu32(uint8_t * buffer,uint32_t value)709 formatu32(uint8_t *buffer, uint32_t value)
710 {
711 buffer[0] = (uint8_t)(value >> 24) & 0xff;
712 buffer[1] = (uint8_t)(value >> 16) & 0xff;
713 buffer[2] = (uint8_t)(value >> 8) & 0xff;
714 buffer[3] = (uint8_t)value & 0xff;
715 return sizeof(uint32_t);
716 }
717
718 /* format a string as (len, string) */
719 static int
formatstring(char * buffer,const uint8_t * s,size_t len)720 formatstring(char *buffer, const uint8_t *s, size_t len)
721 {
722 int cc;
723
724 cc = formatu32((uint8_t *)buffer, (uint32_t)len);
725 (void) memcpy(&buffer[cc], s, len);
726 return cc + (int)len;
727 }
728
729 /* format a bignum, checking for "interesting" high bit values */
730 static int
formatbignum(char * buffer,BIGNUM * bn)731 formatbignum(char *buffer, BIGNUM *bn)
732 {
733 size_t len;
734 uint8_t *cp;
735 int cc;
736
737 len = (size_t) BN_num_bytes(bn);
738 if ((cp = calloc(1, len + 1)) == NULL) {
739 (void) fprintf(stderr, "calloc failure in formatbignum\n");
740 return 0;
741 }
742 (void) BN_bn2bin(bn, cp + 1);
743 cp[0] = 0x0;
744 cc = (cp[1] & 0x80) ? formatstring(buffer, cp, len + 1) : formatstring(buffer, &cp[1], len);
745 free(cp);
746 return cc;
747 }
748
749 #define MAX_PASSPHRASE_ATTEMPTS 3
750 #define INFINITE_ATTEMPTS -1
751
752 /* get the passphrase from the user */
753 static int
find_passphrase(FILE * passfp,const char * id,char * passphrase,size_t size,int attempts)754 find_passphrase(FILE *passfp, const char *id, char *passphrase, size_t size, int attempts)
755 {
756 char prompt[BUFSIZ];
757 char buf[128];
758 char *cp;
759 int cc;
760 int i;
761
762 if (passfp) {
763 if (fgets(passphrase, (int)size, passfp) == NULL) {
764 return 0;
765 }
766 return (int)strlen(passphrase);
767 }
768 for (i = 0 ; i < attempts ; i++) {
769 (void) snprintf(prompt, sizeof(prompt), "Enter passphrase for %.16s: ", id);
770 if ((cp = getpass(prompt)) == NULL) {
771 break;
772 }
773 cc = snprintf(buf, sizeof(buf), "%s", cp);
774 (void) snprintf(prompt, sizeof(prompt), "Repeat passphrase for %.16s: ", id);
775 if ((cp = getpass(prompt)) == NULL) {
776 break;
777 }
778 cc = snprintf(passphrase, size, "%s", cp);
779 if (strcmp(buf, passphrase) == 0) {
780 (void) memset(buf, 0x0, sizeof(buf));
781 return cc;
782 }
783 }
784 (void) memset(buf, 0x0, sizeof(buf));
785 (void) memset(passphrase, 0x0, size);
786 return 0;
787 }
788
789 /***************************************************************************/
790 /* exported functions start here */
791 /***************************************************************************/
792
793 /* initialise a netpgp_t structure */
794 int
netpgp_init(netpgp_t * netpgp)795 netpgp_init(netpgp_t *netpgp)
796 {
797 pgp_io_t *io;
798 time_t t;
799 char id[MAX_ID_LENGTH];
800 char *homedir;
801 char *userid;
802 char *stream;
803 char *passfd;
804 char *results;
805 int coredumps;
806 int last;
807
808 #ifdef HAVE_SYS_RESOURCE_H
809 struct rlimit limit;
810
811 coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
812 if (!coredumps) {
813 (void) memset(&limit, 0x0, sizeof(limit));
814 if (setrlimit(RLIMIT_CORE, &limit) != 0) {
815 (void) fprintf(stderr,
816 "netpgp: warning - can't turn off core dumps\n");
817 coredumps = 1;
818 }
819 }
820 #else
821 coredumps = 1;
822 #endif
823 if ((io = calloc(1, sizeof(*io))) == NULL) {
824 (void) fprintf(stderr, "netpgp_init: bad alloc\n");
825 return 0;
826 }
827 io->outs = stdout;
828 if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
829 strcmp(stream, "<stderr>") == 0) {
830 io->outs = stderr;
831 }
832 io->errs = stderr;
833 if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
834 strcmp(stream, "<stdout>") == 0) {
835 io->errs = stdout;
836 }
837 if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
838 io->res = io->errs;
839 } else if (strcmp(results, "<stdout>") == 0) {
840 io->res = stdout;
841 } else if (strcmp(results, "<stderr>") == 0) {
842 io->res = stderr;
843 } else {
844 if ((io->res = fopen(results, "w")) == NULL) {
845 (void) fprintf(io->errs, "Can't open results %s for writing\n",
846 results);
847 free(io);
848 return 0;
849 }
850 }
851 netpgp->io = io;
852 /* get passphrase from an fd */
853 if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
854 (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
855 (void) fprintf(io->errs, "Can't open fd %s for reading\n",
856 passfd);
857 return 0;
858 }
859 /* warn if core dumps are enabled */
860 if (coredumps) {
861 (void) fprintf(io->errs,
862 "netpgp: warning: core dumps enabled\n");
863 }
864 /* get home directory - where keyrings are in a subdir */
865 if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
866 (void) fprintf(io->errs, "netpgp: bad homedir\n");
867 return 0;
868 }
869 if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
870 /* read from ordinary pgp keyrings */
871 netpgp->pubring = readkeyring(netpgp, "pubring");
872 if (netpgp->pubring == NULL) {
873 return 0;
874 }
875 /* if a userid has been given, we'll use it */
876 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
877 /* also search in config file for default id */
878 (void) memset(id, 0x0, sizeof(id));
879 (void) conffile(netpgp, homedir, id, sizeof(id));
880 if (id[0] != 0x0) {
881 netpgp_setvar(netpgp, "userid", userid = id);
882 }
883 }
884 /* only read secret keys if we need to */
885 if (netpgp_getvar(netpgp, "need seckey")) {
886 /* read the secret ring */
887 netpgp->secring = readkeyring(netpgp, "secring");
888 if (netpgp->secring == NULL) {
889 return 0;
890 }
891 /* now, if we don't have a valid user, use the first in secring */
892 if (!userid && netpgp_getvar(netpgp, "need userid") != NULL) {
893 /* signing - need userid and sec key */
894 (void) memset(id, 0x0, sizeof(id));
895 if (get_first_ring(netpgp->secring, id, sizeof(id), 0)) {
896 netpgp_setvar(netpgp, "userid", userid = id);
897 }
898 }
899 } else if (netpgp_getvar(netpgp, "need userid") != NULL) {
900 /* encrypting - get first in pubring */
901 if (!userid && get_first_ring(netpgp->pubring, id, sizeof(id), 0)) {
902 (void) netpgp_setvar(netpgp, "userid", userid = id);
903 }
904 }
905 if (!userid && netpgp_getvar(netpgp, "need userid")) {
906 /* if we don't have a user id, and we need one, fail */
907 (void) fprintf(io->errs, "Cannot find user id\n");
908 return 0;
909 }
910 } else {
911 /* read from ssh keys */
912 last = (netpgp->pubring != NULL);
913 if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) {
914 return 0;
915 }
916 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
917 get_first_ring(netpgp->pubring, id, sizeof(id), last);
918 netpgp_setvar(netpgp, "userid", userid = id);
919 }
920 if (userid == NULL) {
921 if (netpgp_getvar(netpgp, "need userid") != NULL) {
922 (void) fprintf(io->errs,
923 "Cannot find user id\n");
924 return 0;
925 }
926 } else {
927 (void) netpgp_setvar(netpgp, "userid", userid);
928 }
929 }
930 t = time(NULL);
931 netpgp_setvar(netpgp, "initialised", ctime(&t));
932 return 1;
933 }
934
935 /* finish off with the netpgp_t struct */
936 int
netpgp_end(netpgp_t * netpgp)937 netpgp_end(netpgp_t *netpgp)
938 {
939 unsigned i;
940
941 for (i = 0 ; i < netpgp->c ; i++) {
942 if (netpgp->name[i] != NULL) {
943 free(netpgp->name[i]);
944 }
945 if (netpgp->value[i] != NULL) {
946 free(netpgp->value[i]);
947 }
948 }
949 if (netpgp->name != NULL) {
950 free(netpgp->name);
951 }
952 if (netpgp->value != NULL) {
953 free(netpgp->value);
954 }
955 if (netpgp->pubring != NULL) {
956 pgp_keyring_free(netpgp->pubring);
957 }
958 if (netpgp->secring != NULL) {
959 pgp_keyring_free(netpgp->secring);
960 }
961 free(netpgp->io);
962 return 1;
963 }
964
965 /* list the keys in a keyring */
966 int
netpgp_list_keys(netpgp_t * netpgp,const int psigs)967 netpgp_list_keys(netpgp_t *netpgp, const int psigs)
968 {
969 if (netpgp->pubring == NULL) {
970 (void) fprintf(stderr, "No keyring\n");
971 return 0;
972 }
973 return pgp_keyring_list(netpgp->io, netpgp->pubring, psigs);
974 }
975
976 /* list the keys in a keyring, returning a JSON encoded string */
977 int
netpgp_list_keys_json(netpgp_t * netpgp,char ** json,const int psigs)978 netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs)
979 {
980 mj_t obj;
981 int ret;
982
983 if (netpgp->pubring == NULL) {
984 (void) fprintf(stderr, "No keyring\n");
985 return 0;
986 }
987 (void) memset(&obj, 0x0, sizeof(obj));
988 if (!pgp_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) {
989 (void) fprintf(stderr, "No keys in keyring\n");
990 return 0;
991 }
992 ret = mj_asprint(json, &obj, MJ_JSON_ENCODE);
993 mj_delete(&obj);
994 return ret;
995 }
996
997 DEFINE_ARRAY(strings_t, char *);
998
999 #ifndef HKP_VERSION
1000 #define HKP_VERSION 1
1001 #endif
1002
1003 /* find and list some keys in a keyring */
1004 int
netpgp_match_keys(netpgp_t * netpgp,char * name,const char * fmt,void * vp,const int psigs)1005 netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
1006 {
1007 const pgp_key_t *key;
1008 unsigned k;
1009 strings_t pubs;
1010 FILE *fp = (FILE *)vp;
1011
1012 if (name[0] == '0' && name[1] == 'x') {
1013 name += 2;
1014 }
1015 (void) memset(&pubs, 0x0, sizeof(pubs));
1016 k = 0;
1017 do {
1018 key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1019 name, &k);
1020 if (key != NULL) {
1021 ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
1022 "netpgp_match_keys", return 0);
1023 if (strcmp(fmt, "mr") == 0) {
1024 pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1025 key, &pubs.v[pubs.c],
1026 &key->key.pubkey, psigs);
1027 } else {
1028 pgp_sprint_keydata(netpgp->io, netpgp->pubring,
1029 key, &pubs.v[pubs.c],
1030 "signature ",
1031 &key->key.pubkey, psigs);
1032 }
1033 if (pubs.v[pubs.c] != NULL) {
1034 pubs.c += 1;
1035 }
1036 k += 1;
1037 }
1038 } while (key != NULL);
1039 if (strcmp(fmt, "mr") == 0) {
1040 (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
1041 } else {
1042 (void) fprintf(fp, "%d key%s found\n", pubs.c,
1043 (pubs.c == 1) ? "" : "s");
1044 }
1045 for (k = 0 ; k < pubs.c ; k++) {
1046 (void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
1047 free(pubs.v[k]);
1048 }
1049 free(pubs.v);
1050 return pubs.c;
1051 }
1052
1053 /* find and list some keys in a keyring - return JSON string */
1054 int
netpgp_match_keys_json(netpgp_t * netpgp,char ** json,char * name,const char * fmt,const int psigs)1055 netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs)
1056 {
1057 const pgp_key_t *key;
1058 unsigned k;
1059 mj_t id_array;
1060 char *newkey;
1061 int ret;
1062
1063 if (name[0] == '0' && name[1] == 'x') {
1064 name += 2;
1065 }
1066 (void) memset(&id_array, 0x0, sizeof(id_array));
1067 k = 0;
1068 *json = NULL;
1069 mj_create(&id_array, "array");
1070 do {
1071 key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1072 name, &k);
1073 if (key != NULL) {
1074 if (strcmp(fmt, "mr") == 0) {
1075 pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1076 key, &newkey,
1077 &key->key.pubkey, 0);
1078 if (newkey) {
1079 printf("%s\n", newkey);
1080 free(newkey);
1081 }
1082 } else {
1083 ALLOC(mj_t, id_array.value.v, id_array.size,
1084 id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
1085 pgp_sprint_mj(netpgp->io, netpgp->pubring,
1086 key, &id_array.value.v[id_array.c++],
1087 "signature",
1088 &key->key.pubkey, psigs);
1089 }
1090 k += 1;
1091 }
1092 } while (key != NULL);
1093 ret = mj_asprint(json, &id_array, MJ_JSON_ENCODE);
1094 mj_delete(&id_array);
1095 return ret;
1096 }
1097
1098 /* find and list some public keys in a keyring */
1099 int
netpgp_match_pubkeys(netpgp_t * netpgp,char * name,void * vp)1100 netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
1101 {
1102 const pgp_key_t *key;
1103 unsigned k;
1104 ssize_t cc;
1105 char out[1024 * 64];
1106 FILE *fp = (FILE *)vp;
1107
1108 k = 0;
1109 do {
1110 key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1111 name, &k);
1112 if (key != NULL) {
1113 cc = pgp_sprint_pubkey(key, out, sizeof(out));
1114 (void) fprintf(fp, "%.*s", (int)cc, out);
1115 k += 1;
1116 }
1117 } while (key != NULL);
1118 return k;
1119 }
1120
1121 /* find a key in a keyring */
1122 int
netpgp_find_key(netpgp_t * netpgp,char * id)1123 netpgp_find_key(netpgp_t *netpgp, char *id)
1124 {
1125 pgp_io_t *io;
1126
1127 io = netpgp->io;
1128 if (id == NULL) {
1129 (void) fprintf(io->errs, "NULL id to search for\n");
1130 return 0;
1131 }
1132 return pgp_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
1133 }
1134
1135 /* get a key in a keyring */
1136 char *
netpgp_get_key(netpgp_t * netpgp,const char * name,const char * fmt)1137 netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
1138 {
1139 const pgp_key_t *key;
1140 char *newkey;
1141
1142 if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1143 return NULL;
1144 }
1145 if (strcmp(fmt, "mr") == 0) {
1146 return (pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1147 key, &newkey,
1148 &key->key.pubkey,
1149 netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1150 }
1151 return (pgp_sprint_keydata(netpgp->io, netpgp->pubring,
1152 key, &newkey, "signature",
1153 &key->key.pubkey,
1154 netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1155 }
1156
1157 /* export a given key */
1158 char *
netpgp_export_key(netpgp_t * netpgp,char * name)1159 netpgp_export_key(netpgp_t *netpgp, char *name)
1160 {
1161 const pgp_key_t *key;
1162 pgp_io_t *io;
1163
1164 io = netpgp->io;
1165 if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1166 return NULL;
1167 }
1168 return pgp_export_key(io, key, NULL);
1169 }
1170
1171 #define IMPORT_ARMOR_HEAD "-----BEGIN PGP PUBLIC KEY BLOCK-----"
1172
1173 /* import a key into our keyring */
1174 int
netpgp_import_key(netpgp_t * netpgp,char * f)1175 netpgp_import_key(netpgp_t *netpgp, char *f)
1176 {
1177 pgp_io_t *io;
1178 unsigned realarmor;
1179 int done;
1180 pgp_keyring_t *keyring;
1181 pgp_key_t *key;
1182 const char *ringname;
1183 int rv;
1184
1185 io = netpgp->io;
1186
1187 if (f == NULL) {
1188 (void) fprintf(io->errs, "No input file given\n");
1189 return 0;
1190 }
1191
1192 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1193 (void) fprintf(io->errs, "netpgp_import_key: bad alloc\n");
1194 return 0;
1195 }
1196
1197 realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
1198 done = pgp_keyring_fileread(keyring, realarmor, f);
1199 if (!done || keyring->keyc == 0) {
1200 (void) fprintf(io->errs, "Cannot import key from file %s\n", f);
1201 pgp_keyring_free(keyring);
1202 return 0;
1203 }
1204 done = pgp_keyring_list(io, keyring, 0);
1205 if (!done)
1206 return 0;
1207
1208 key = keyring->keys;
1209
1210 if (key->type == PGP_PTAG_CT_PUBLIC_KEY) {
1211 ringname = "pubring";
1212 } else {
1213 ringname = "secring";
1214 }
1215
1216 if (!done) {
1217 pgp_keyring_free(keyring);
1218 (void) fprintf(io->errs, "Bad append\n");
1219 return 0;
1220 }
1221
1222 rv = appendtokeyring(netpgp, ringname, key);
1223 pgp_keyring_free(keyring);
1224
1225 return rv;
1226 }
1227
1228 #define ID_OFFSET 38
1229
1230 /* generate a new key */
1231 int
netpgp_generate_key(netpgp_t * netpgp,char * id,int numbits)1232 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
1233 {
1234 pgp_output_t *create;
1235 const unsigned noarmor = 0;
1236 pgp_key_t *key;
1237 pgp_io_t *io;
1238 uint8_t *uid;
1239 char passphrase[128];
1240 char newid[1024];
1241 char filename[MAXPATHLEN];
1242 char dir[MAXPATHLEN];
1243 char *cp;
1244 char *ringfile;
1245 char *numtries;
1246 int attempts;
1247 int passc;
1248 int fd;
1249 int cc;
1250 int rv = 0;
1251
1252 uid = NULL;
1253 io = netpgp->io;
1254 /* generate a new key */
1255 if (id) {
1256 (void) snprintf(newid, sizeof(newid), "%s", id);
1257 } else {
1258 (void) snprintf(newid, sizeof(newid),
1259 "RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
1260 }
1261 uid = (uint8_t *)newid;
1262 key = pgp_rsa_new_selfsign_key(numbits, 65537UL, uid,
1263 netpgp_getvar(netpgp, "hash"),
1264 netpgp_getvar(netpgp, "cipher"));
1265 if (key == NULL) {
1266 (void) fprintf(io->errs, "Cannot generate key\n");
1267 return 0;
1268 }
1269 cp = NULL;
1270 pgp_sprint_keydata(netpgp->io, NULL, key, &cp, "signature ", &key->key.seckey.pubkey, 0);
1271 (void) fprintf(stdout, "%s", cp);
1272 /* write public key */
1273 cc = snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[ID_OFFSET]);
1274 netpgp_setvar(netpgp, "generated userid", &dir[cc - 16]);
1275 if (mkdir(dir, 0700) < 0) {
1276 (void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
1277 goto out;
1278 }
1279 (void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
1280 (void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
1281 if (!appendkey(io, key, ringfile)) {
1282 (void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile);
1283 goto out;
1284 }
1285 if (netpgp->pubring != NULL) {
1286 pgp_keyring_free(netpgp->pubring);
1287 }
1288 /* write secret key */
1289 (void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
1290 if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
1291 fd = pgp_setup_file_write(&create, ringfile, 0);
1292 }
1293 if (fd < 0) {
1294 (void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
1295 goto out;
1296 }
1297 /* get the passphrase */
1298 if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1299 (attempts = atoi(numtries)) <= 0) {
1300 attempts = MAX_PASSPHRASE_ATTEMPTS;
1301 } else if (strcmp(numtries, "unlimited") == 0) {
1302 attempts = INFINITE_ATTEMPTS;
1303 }
1304 passc = find_passphrase(netpgp->passfp, &cp[ID_OFFSET], passphrase, sizeof(passphrase), attempts);
1305 if (!pgp_write_xfer_seckey(create, key, (uint8_t *)passphrase, (const unsigned)passc, noarmor)) {
1306 (void) fprintf(io->errs, "Cannot write seckey\n");
1307 goto out1;
1308 }
1309 rv = 1;
1310 out1:
1311 pgp_teardown_file_write(create, fd);
1312 if (netpgp->secring != NULL) {
1313 pgp_keyring_free(netpgp->secring);
1314 }
1315 out:
1316 pgp_keydata_free(key);
1317 free(cp);
1318 return rv;
1319 }
1320
1321 /* encrypt a file */
1322 int
netpgp_encrypt_file(netpgp_t * netpgp,const char * userid,const char * f,char * out,int armored)1323 netpgp_encrypt_file(netpgp_t *netpgp,
1324 const char *userid,
1325 const char *f,
1326 char *out,
1327 int armored)
1328 {
1329 const pgp_key_t *key;
1330 const unsigned overwrite = 1;
1331 const char *suffix;
1332 pgp_io_t *io;
1333 char outname[MAXPATHLEN];
1334
1335 io = netpgp->io;
1336 if (f == NULL) {
1337 (void) fprintf(io->errs,
1338 "netpgp_encrypt_file: no filename specified\n");
1339 return 0;
1340 }
1341 suffix = (armored) ? ".asc" : ".gpg";
1342 /* get key with which to sign */
1343 if ((key = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1344 return 0;
1345 }
1346 if (out == NULL) {
1347 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
1348 out = outname;
1349 }
1350 return (int)pgp_encrypt_file(io, f, out, key, (unsigned)armored,
1351 overwrite, netpgp_getvar(netpgp, "cipher"));
1352 }
1353
1354 #define ARMOR_HEAD "-----BEGIN PGP MESSAGE-----"
1355
1356 /* decrypt a file */
1357 int
netpgp_decrypt_file(netpgp_t * netpgp,const char * f,char * out,int armored)1358 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
1359 {
1360 const unsigned overwrite = 1;
1361 pgp_io_t *io;
1362 unsigned realarmor;
1363 unsigned sshkeys;
1364 char *numtries;
1365 int attempts;
1366
1367 __PGP_USED(armored);
1368 io = netpgp->io;
1369 if (f == NULL) {
1370 (void) fprintf(io->errs,
1371 "netpgp_decrypt_file: no filename specified\n");
1372 return 0;
1373 }
1374 realarmor = isarmoured(io, f, NULL, ARMOR_HEAD);
1375 sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1376 if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1377 (attempts = atoi(numtries)) <= 0) {
1378 attempts = MAX_PASSPHRASE_ATTEMPTS;
1379 } else if (strcmp(numtries, "unlimited") == 0) {
1380 attempts = INFINITE_ATTEMPTS;
1381 }
1382 return pgp_decrypt_file(netpgp->io, f, out, netpgp->secring,
1383 netpgp->pubring,
1384 realarmor, overwrite, sshkeys,
1385 netpgp->passfp, attempts, get_passphrase_cb);
1386 }
1387
1388 /* sign a file */
1389 int
netpgp_sign_file(netpgp_t * netpgp,const char * userid,const char * f,char * out,int armored,int cleartext,int detached)1390 netpgp_sign_file(netpgp_t *netpgp,
1391 const char *userid,
1392 const char *f,
1393 char *out,
1394 int armored,
1395 int cleartext,
1396 int detached)
1397 {
1398 const pgp_key_t *keypair;
1399 const pgp_key_t *pubkey;
1400 const unsigned overwrite = 1;
1401 pgp_seckey_t *seckey;
1402 const char *hashalg;
1403 pgp_io_t *io;
1404 char *numtries;
1405 int attempts;
1406 int ret;
1407 int i;
1408
1409 io = netpgp->io;
1410 if (f == NULL) {
1411 (void) fprintf(io->errs,
1412 "netpgp_sign_file: no filename specified\n");
1413 return 0;
1414 }
1415 /* get key with which to sign */
1416 if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1417 return 0;
1418 }
1419 ret = 1;
1420 if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1421 (attempts = atoi(numtries)) <= 0) {
1422 attempts = MAX_PASSPHRASE_ATTEMPTS;
1423 } else if (strcmp(numtries, "unlimited") == 0) {
1424 attempts = INFINITE_ATTEMPTS;
1425 }
1426 for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1427 if (netpgp->passfp == NULL) {
1428 /* print out the user id */
1429 pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1430 if (pubkey == NULL) {
1431 (void) fprintf(io->errs,
1432 "netpgp: warning - using pubkey from secring\n");
1433 pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1434 &keypair->key.seckey.pubkey, 0);
1435 } else {
1436 pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1437 &pubkey->key.pubkey, 0);
1438 }
1439 }
1440 if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
1441 /* now decrypt key */
1442 seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1443 if (seckey == NULL) {
1444 (void) fprintf(io->errs, "Bad passphrase\n");
1445 }
1446 } else {
1447 pgp_keyring_t *secring;
1448
1449 secring = netpgp->secring;
1450 seckey = &secring->keys[0].key.seckey;
1451 }
1452 }
1453 if (seckey == NULL) {
1454 (void) fprintf(io->errs, "Bad passphrase\n");
1455 return 0;
1456 }
1457 /* sign file */
1458 hashalg = netpgp_getvar(netpgp, "hash");
1459 if (seckey->pubkey.alg == PGP_PKA_DSA) {
1460 hashalg = "sha1";
1461 }
1462 if (detached) {
1463 ret = pgp_sign_detached(io, f, out, seckey, hashalg,
1464 get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1465 get_duration(netpgp_getvar(netpgp, "duration")),
1466 (unsigned)armored,
1467 overwrite);
1468 } else {
1469 ret = pgp_sign_file(io, f, out, seckey, hashalg,
1470 get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1471 get_duration(netpgp_getvar(netpgp, "duration")),
1472 (unsigned)armored, (unsigned)cleartext,
1473 overwrite);
1474 }
1475 pgp_forget(seckey, sizeof(*seckey));
1476 return ret;
1477 }
1478
1479 #define ARMOR_SIG_HEAD "-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"
1480
1481 /* verify a file */
1482 int
netpgp_verify_file(netpgp_t * netpgp,const char * in,const char * out,int armored)1483 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
1484 {
1485 pgp_validation_t result;
1486 pgp_io_t *io;
1487 unsigned realarmor;
1488
1489 __PGP_USED(armored);
1490 (void) memset(&result, 0x0, sizeof(result));
1491 io = netpgp->io;
1492 if (in == NULL) {
1493 (void) fprintf(io->errs,
1494 "netpgp_verify_file: no filename specified\n");
1495 return 0;
1496 }
1497 realarmor = isarmoured(io, in, NULL, ARMOR_SIG_HEAD);
1498 if (pgp_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
1499 resultp(io, in, &result, netpgp->pubring);
1500 return 1;
1501 }
1502 if (result.validc + result.invalidc + result.unknownc == 0) {
1503 (void) fprintf(io->errs,
1504 "\"%s\": No signatures found - is this a signed file?\n",
1505 in);
1506 } else if (result.invalidc == 0 && result.unknownc == 0) {
1507 (void) fprintf(io->errs,
1508 "\"%s\": file verification failure: invalid signature time\n", in);
1509 } else {
1510 (void) fprintf(io->errs,
1511 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
1512 in, result.invalidc, result.unknownc);
1513 }
1514 return 0;
1515 }
1516
1517 /* sign some memory */
1518 int
netpgp_sign_memory(netpgp_t * netpgp,const char * userid,char * mem,size_t size,char * out,size_t outsize,const unsigned armored,const unsigned cleartext)1519 netpgp_sign_memory(netpgp_t *netpgp,
1520 const char *userid,
1521 char *mem,
1522 size_t size,
1523 char *out,
1524 size_t outsize,
1525 const unsigned armored,
1526 const unsigned cleartext)
1527 {
1528 const pgp_key_t *keypair;
1529 const pgp_key_t *pubkey;
1530 pgp_seckey_t *seckey;
1531 pgp_memory_t *signedmem;
1532 const char *hashalg;
1533 pgp_io_t *io;
1534 char *numtries;
1535 int attempts;
1536 int ret;
1537 int i;
1538
1539 io = netpgp->io;
1540 if (mem == NULL) {
1541 (void) fprintf(io->errs,
1542 "netpgp_sign_memory: no memory to sign\n");
1543 return 0;
1544 }
1545 if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1546 return 0;
1547 }
1548 ret = 1;
1549 if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1550 (attempts = atoi(numtries)) <= 0) {
1551 attempts = MAX_PASSPHRASE_ATTEMPTS;
1552 } else if (strcmp(numtries, "unlimited") == 0) {
1553 attempts = INFINITE_ATTEMPTS;
1554 }
1555 for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1556 if (netpgp->passfp == NULL) {
1557 /* print out the user id */
1558 pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1559 if (pubkey == NULL) {
1560 (void) fprintf(io->errs,
1561 "netpgp: warning - using pubkey from secring\n");
1562 pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1563 &keypair->key.seckey.pubkey, 0);
1564 } else {
1565 pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1566 &pubkey->key.pubkey, 0);
1567 }
1568 }
1569 if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
1570 /* now decrypt key */
1571 seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1572 if (seckey == NULL) {
1573 (void) fprintf(io->errs, "Bad passphrase\n");
1574 }
1575 } else {
1576 pgp_keyring_t *secring;
1577
1578 secring = netpgp->secring;
1579 seckey = &secring->keys[0].key.seckey;
1580 }
1581 }
1582 if (seckey == NULL) {
1583 (void) fprintf(io->errs, "Bad passphrase\n");
1584 return 0;
1585 }
1586 /* sign file */
1587 (void) memset(out, 0x0, outsize);
1588 hashalg = netpgp_getvar(netpgp, "hash");
1589 if (seckey->pubkey.alg == PGP_PKA_DSA) {
1590 hashalg = "sha1";
1591 }
1592 signedmem = pgp_sign_buf(io, mem, size, seckey,
1593 get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1594 get_duration(netpgp_getvar(netpgp, "duration")),
1595 hashalg, armored, cleartext);
1596 if (signedmem) {
1597 size_t m;
1598
1599 m = MIN(pgp_mem_len(signedmem), outsize);
1600 (void) memcpy(out, pgp_mem_data(signedmem), m);
1601 pgp_memory_free(signedmem);
1602 ret = (int)m;
1603 } else {
1604 ret = 0;
1605 }
1606 pgp_forget(seckey, sizeof(*seckey));
1607 return ret;
1608 }
1609
1610 /* verify memory */
1611 int
netpgp_verify_memory(netpgp_t * netpgp,const void * in,const size_t size,void * out,size_t outsize,const int armored)1612 netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
1613 void *out, size_t outsize, const int armored)
1614 {
1615 pgp_validation_t result;
1616 pgp_memory_t *signedmem;
1617 pgp_memory_t *cat;
1618 pgp_io_t *io;
1619 size_t m;
1620 int ret;
1621
1622 (void) memset(&result, 0x0, sizeof(result));
1623 io = netpgp->io;
1624 if (in == NULL) {
1625 (void) fprintf(io->errs,
1626 "netpgp_verify_memory: no memory to verify\n");
1627 return 0;
1628 }
1629 signedmem = pgp_memory_new();
1630 pgp_memory_add(signedmem, in, size);
1631 if (out) {
1632 cat = pgp_memory_new();
1633 }
1634 ret = pgp_validate_mem(io, &result, signedmem,
1635 (out) ? &cat : NULL,
1636 armored, netpgp->pubring);
1637 /* signedmem is freed from pgp_validate_mem */
1638 if (ret) {
1639 resultp(io, "<stdin>", &result, netpgp->pubring);
1640 if (out) {
1641 m = MIN(pgp_mem_len(cat), outsize);
1642 (void) memcpy(out, pgp_mem_data(cat), m);
1643 pgp_memory_free(cat);
1644 } else {
1645 m = 1;
1646 }
1647 return (int)m;
1648 }
1649 if (result.validc + result.invalidc + result.unknownc == 0) {
1650 (void) fprintf(io->errs,
1651 "No signatures found - is this memory signed?\n");
1652 } else if (result.invalidc == 0 && result.unknownc == 0) {
1653 (void) fprintf(io->errs,
1654 "memory verification failure: invalid signature time\n");
1655 } else {
1656 (void) fprintf(io->errs,
1657 "memory verification failure: %u invalid signatures, %u unknown signatures\n",
1658 result.invalidc, result.unknownc);
1659 }
1660 return 0;
1661 }
1662
1663 /* encrypt some memory */
1664 int
netpgp_encrypt_memory(netpgp_t * netpgp,const char * userid,void * in,const size_t insize,char * out,size_t outsize,int armored)1665 netpgp_encrypt_memory(netpgp_t *netpgp,
1666 const char *userid,
1667 void *in,
1668 const size_t insize,
1669 char *out,
1670 size_t outsize,
1671 int armored)
1672 {
1673 const pgp_key_t *keypair;
1674 pgp_memory_t *enc;
1675 pgp_io_t *io;
1676 size_t m;
1677
1678 io = netpgp->io;
1679 if (in == NULL) {
1680 (void) fprintf(io->errs,
1681 "netpgp_encrypt_buf: no memory to encrypt\n");
1682 return 0;
1683 }
1684 if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1685 return 0;
1686 }
1687 if (in == out) {
1688 (void) fprintf(io->errs,
1689 "netpgp_encrypt_buf: input and output bufs need to be different\n");
1690 return 0;
1691 }
1692 if (outsize < insize) {
1693 (void) fprintf(io->errs,
1694 "netpgp_encrypt_buf: input size is larger than output size\n");
1695 return 0;
1696 }
1697 enc = pgp_encrypt_buf(io, in, insize, keypair, (unsigned)armored,
1698 netpgp_getvar(netpgp, "cipher"));
1699 m = MIN(pgp_mem_len(enc), outsize);
1700 (void) memcpy(out, pgp_mem_data(enc), m);
1701 pgp_memory_free(enc);
1702 return (int)m;
1703 }
1704
1705 /* decrypt a chunk of memory */
1706 int
netpgp_decrypt_memory(netpgp_t * netpgp,const void * input,const size_t insize,char * out,size_t outsize,const int armored)1707 netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
1708 char *out, size_t outsize, const int armored)
1709 {
1710 pgp_memory_t *mem;
1711 pgp_io_t *io;
1712 unsigned realarmour;
1713 unsigned sshkeys;
1714 size_t m;
1715 char *numtries;
1716 int attempts;
1717
1718 __PGP_USED(armored);
1719 io = netpgp->io;
1720 if (input == NULL) {
1721 (void) fprintf(io->errs,
1722 "netpgp_decrypt_memory: no memory\n");
1723 return 0;
1724 }
1725 realarmour = isarmoured(io, NULL, input, ARMOR_HEAD);
1726 sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1727 if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1728 (attempts = atoi(numtries)) <= 0) {
1729 attempts = MAX_PASSPHRASE_ATTEMPTS;
1730 } else if (strcmp(numtries, "unlimited") == 0) {
1731 attempts = INFINITE_ATTEMPTS;
1732 }
1733 mem = pgp_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
1734 netpgp->pubring,
1735 realarmour, sshkeys,
1736 netpgp->passfp,
1737 attempts,
1738 get_passphrase_cb);
1739 if (mem == NULL) {
1740 return -1;
1741 }
1742 m = MIN(pgp_mem_len(mem), outsize);
1743 (void) memcpy(out, pgp_mem_data(mem), m);
1744 pgp_memory_free(mem);
1745 return (int)m;
1746 }
1747
1748 /* wrappers for the ops_debug_level functions we added to openpgpsdk */
1749
1750 /* set the debugging level per filename */
1751 int
netpgp_set_debug(const char * f)1752 netpgp_set_debug(const char *f)
1753 {
1754 return pgp_set_debug_level(f);
1755 }
1756
1757 /* get the debugging level per filename */
1758 int
netpgp_get_debug(const char * f)1759 netpgp_get_debug(const char *f)
1760 {
1761 return pgp_get_debug_level(f);
1762 }
1763
1764 /* return the version for the library */
1765 const char *
netpgp_get_info(const char * type)1766 netpgp_get_info(const char *type)
1767 {
1768 return pgp_get_info(type);
1769 }
1770
1771 /* list all the packets in a file */
1772 int
netpgp_list_packets(netpgp_t * netpgp,char * f,int armor,char * pubringname)1773 netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
1774 {
1775 pgp_keyring_t *keyring;
1776 const unsigned noarmor = 0;
1777 struct stat st;
1778 pgp_io_t *io;
1779 char ringname[MAXPATHLEN];
1780 char *homedir;
1781 int ret;
1782
1783 io = netpgp->io;
1784 if (f == NULL) {
1785 (void) fprintf(io->errs, "No file containing packets\n");
1786 return 0;
1787 }
1788 if (stat(f, &st) < 0) {
1789 (void) fprintf(io->errs, "No such file '%s'\n", f);
1790 return 0;
1791 }
1792 homedir = netpgp_getvar(netpgp, "homedir");
1793 if (pubringname == NULL) {
1794 (void) snprintf(ringname, sizeof(ringname),
1795 "%s/pubring.gpg", homedir);
1796 pubringname = ringname;
1797 }
1798 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1799 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
1800 return 0;
1801 }
1802 if (!pgp_keyring_fileread(keyring, noarmor, pubringname)) {
1803 free(keyring);
1804 (void) fprintf(io->errs, "Cannot read pub keyring %s\n",
1805 pubringname);
1806 return 0;
1807 }
1808 netpgp->pubring = keyring;
1809 netpgp_setvar(netpgp, "pubring", pubringname);
1810 ret = pgp_list_packets(io, f, (unsigned)armor,
1811 netpgp->secring,
1812 netpgp->pubring,
1813 netpgp->passfp,
1814 get_passphrase_cb);
1815 free(keyring);
1816 return ret;
1817 }
1818
1819 /* set a variable */
1820 int
netpgp_setvar(netpgp_t * netpgp,const char * name,const char * value)1821 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
1822 {
1823 char *newval;
1824 int i;
1825
1826 /* protect against the case where 'value' is netpgp->value[i] */
1827 newval = netpgp_strdup(value);
1828 if ((i = findvar(netpgp, name)) < 0) {
1829 /* add the element to the array */
1830 if (size_arrays(netpgp, netpgp->size + 15)) {
1831 netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
1832 }
1833 } else {
1834 /* replace the element in the array */
1835 if (netpgp->value[i]) {
1836 free(netpgp->value[i]);
1837 netpgp->value[i] = NULL;
1838 }
1839 }
1840 /* sanity checks for range of values */
1841 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
1842 if (pgp_str_to_hash_alg(newval) == PGP_HASH_UNKNOWN) {
1843 free(newval);
1844 return 0;
1845 }
1846 }
1847 netpgp->value[i] = newval;
1848 return 1;
1849 }
1850
1851 /* unset a variable */
1852 int
netpgp_unsetvar(netpgp_t * netpgp,const char * name)1853 netpgp_unsetvar(netpgp_t *netpgp, const char *name)
1854 {
1855 int i;
1856
1857 if ((i = findvar(netpgp, name)) >= 0) {
1858 if (netpgp->value[i]) {
1859 free(netpgp->value[i]);
1860 netpgp->value[i] = NULL;
1861 }
1862 netpgp->value[i] = NULL;
1863 return 1;
1864 }
1865 return 0;
1866 }
1867
1868 /* get a variable's value (NULL if not set) */
1869 char *
netpgp_getvar(netpgp_t * netpgp,const char * name)1870 netpgp_getvar(netpgp_t *netpgp, const char *name)
1871 {
1872 int i;
1873
1874 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
1875 }
1876
1877 /* increment a value */
1878 int
netpgp_incvar(netpgp_t * netpgp,const char * name,const int delta)1879 netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
1880 {
1881 char *cp;
1882 char num[16];
1883 int val;
1884
1885 val = 0;
1886 if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
1887 val = atoi(cp);
1888 }
1889 (void) snprintf(num, sizeof(num), "%d", val + delta);
1890 netpgp_setvar(netpgp, name, num);
1891 return 1;
1892 }
1893
1894 /* set the home directory value to "home/subdir" */
1895 int
netpgp_set_homedir(netpgp_t * netpgp,char * home,const char * subdir,const int quiet)1896 netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
1897 {
1898 struct stat st;
1899 char d[MAXPATHLEN];
1900
1901 if (home == NULL) {
1902 if (!quiet) {
1903 (void) fprintf(stderr, "NULL HOME directory\n");
1904 }
1905 return 0;
1906 }
1907 (void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
1908 if (stat(d, &st) == 0) {
1909 if ((st.st_mode & S_IFMT) == S_IFDIR) {
1910 netpgp_setvar(netpgp, "homedir", d);
1911 return 1;
1912 }
1913 (void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
1914 d);
1915 return 0;
1916 }
1917 if (!quiet) {
1918 (void) fprintf(stderr,
1919 "netpgp: warning homedir \"%s\" not found\n", d);
1920 }
1921 netpgp_setvar(netpgp, "homedir", d);
1922 return 1;
1923 }
1924
1925 /* validate all sigs in the pub keyring */
1926 int
netpgp_validate_sigs(netpgp_t * netpgp)1927 netpgp_validate_sigs(netpgp_t *netpgp)
1928 {
1929 pgp_validation_t result;
1930
1931 return (int)pgp_validate_all_sigs(&result, netpgp->pubring, NULL);
1932 }
1933
1934 /* print the json out on 'fp' */
1935 int
netpgp_format_json(void * vp,const char * json,const int psigs)1936 netpgp_format_json(void *vp, const char *json, const int psigs)
1937 {
1938 mj_t ids;
1939 FILE *fp;
1940 int from;
1941 int idc;
1942 int tok;
1943 int to;
1944 int i;
1945
1946 if ((fp = (FILE *)vp) == NULL || json == NULL) {
1947 return 0;
1948 }
1949 /* ids is an array of strings, each containing 1 entry */
1950 (void) memset(&ids, 0x0, sizeof(ids));
1951 from = to = tok = 0;
1952 /* convert from string into an mj structure */
1953 (void) mj_parse(&ids, json, &from, &to, &tok);
1954 if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) {
1955 idc = 0;
1956 }
1957 (void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s");
1958 for (i = 0 ; i < idc ; i++) {
1959 format_json_key(fp, &ids.value.v[i], psigs);
1960 }
1961 /* clean up */
1962 mj_delete(&ids);
1963 return idc;
1964 }
1965
1966 /* find a key in keyring, and write it in ssh format */
1967 int
netpgp_write_sshkey(netpgp_t * netpgp,char * s,const char * userid,char * out,size_t size)1968 netpgp_write_sshkey(netpgp_t *netpgp, char *s, const char *userid, char *out, size_t size)
1969 {
1970 const pgp_key_t *key;
1971 pgp_keyring_t *keyring;
1972 pgp_io_t *io;
1973 unsigned k;
1974 size_t cc;
1975 char f[MAXPATHLEN];
1976
1977 keyring = NULL;
1978 io = NULL;
1979 cc = 0;
1980 if ((io = calloc(1, sizeof(pgp_io_t))) == NULL) {
1981 (void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 1\n");
1982 goto done;
1983 }
1984 io->outs = stdout;
1985 io->errs = stderr;
1986 io->res = stderr;
1987 netpgp->io = io;
1988 /* write new to temp file */
1989 savepubkey(s, f, sizeof(f));
1990 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1991 (void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 2\n");
1992 goto done;
1993 }
1994 if (!pgp_keyring_fileread(netpgp->pubring = keyring, 1, f)) {
1995 (void) fprintf(stderr, "can't import key\n");
1996 goto done;
1997 }
1998 /* get rsa key */
1999 k = 0;
2000 key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring, userid, &k);
2001 if (key == NULL) {
2002 (void) fprintf(stderr, "no key found for '%s'\n", userid);
2003 goto done;
2004 }
2005 if (key->key.pubkey.alg != PGP_PKA_RSA) {
2006 /* we're not interested in supporting DSA either :-) */
2007 (void) fprintf(stderr, "key not RSA '%s'\n", userid);
2008 goto done;
2009 }
2010 /* XXX - check trust sigs */
2011 /* XXX - check expiry */
2012 /* XXX - check start */
2013 /* XXX - check not weak key */
2014 /* get rsa e and n */
2015 (void) memset(out, 0x0, size);
2016 cc = formatstring((char *)out, (const uint8_t *)"ssh-rsa", 7);
2017 cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.e);
2018 cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.n);
2019 done:
2020 if (io) {
2021 free(io);
2022 }
2023 if (keyring) {
2024 free(keyring);
2025 }
2026 return (int)cc;
2027 }
2028