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