Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2021 Kyle Evans <kevans@FreeBSD.org>
3 : : *
4 : : * Redistribution and use in source and binary forms, with or without
5 : : * modification, are permitted provided that the following conditions
6 : : * are met:
7 : : * 1. Redistributions of source code must retain the above copyright
8 : : * notice, this list of conditions and the following disclaimer
9 : : * in this position and unchanged.
10 : : * 2. Redistributions in binary form must reproduce the above copyright
11 : : * notice, this list of conditions and the following disclaimer in the
12 : : * documentation and/or other materials provided with the distribution.
13 : : *
14 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 : : */
25 : :
26 : : #ifdef HAVE_CONFIG_H
27 : : #include "pkg_config.h"
28 : : #endif
29 : :
30 : : #include <sys/uio.h>
31 : :
32 : : #include <bsd_compat.h>
33 : : #include <assert.h>
34 : : #include <err.h>
35 : : #include <getopt.h>
36 : : #include <signal.h>
37 : : #include <stdio.h>
38 : : #include <string.h>
39 : :
40 : : #ifdef HAVE_READPASSPHRASE_H
41 : : #include <readpassphrase.h>
42 : : #elif defined(HAVE_BSD_READPASSPHRASE_H)
43 : : #include <bsd/readpassphrase.h>
44 : : #else
45 : : #include "readpassphrase_compat.h"
46 : : #endif
47 : :
48 : : #include <unistd.h>
49 : :
50 : : #include <pkg.h>
51 : : #include "pkgcli.h"
52 : :
53 : : enum {
54 : : ARG_CREATE = CHAR_MAX + 1,
55 : : ARG_PUBLIC,
56 : : ARG_SIGN,
57 : : };
58 : :
59 : : typedef enum {
60 : : MODE_UNSPECIFIED = 0,
61 : : MODE_CREATE,
62 : : MODE_PUBLIC,
63 : : MODE_SIGN,
64 : : } key_mode_t;
65 : :
66 : : void
67 : 0 : usage_key(void)
68 : : {
69 : 0 : fprintf(stderr, "Usage: pkg key [--create | --public | --sign] [-t <type>] "
70 : : "<key-path>\n");
71 : 0 : fprintf(stderr, "For more information see 'pkg help key'.\n");
72 : 0 : }
73 : :
74 : : static int
75 : 12 : key_create(struct pkg_key *key, int argc __unused, char *argv[] __unused)
76 : : {
77 : : /* No arguments to setup for now. */
78 : 12 : return (pkg_key_create(key, NULL, 0));
79 : : }
80 : :
81 : : static int
82 : 13 : key_pubout(struct pkg_key *key)
83 : : {
84 : 13 : char *keybuf = NULL;
85 : : size_t keylen;
86 : : int ret;
87 : :
88 : 13 : ret = pkg_key_pubkey(key, &keybuf, &keylen);
89 [ - + ]: 13 : if (ret != EPKG_OK)
90 : 0 : return (ret);
91 : :
92 : 13 : fwrite(keybuf, keylen, 1, stdout);
93 : 13 : free(keybuf);
94 : 13 : return (0);
95 : 13 : }
96 : :
97 : : static int
98 : 2 : key_sign_data(struct pkg_key *key, const char *name)
99 : : {
100 : : char buf[BUFSIZ];
101 : : xstring *datastr;
102 : : char *data;
103 : : unsigned char *sig;
104 : : size_t datasz, readsz, siglen;
105 : : FILE *datafile;
106 : : int rc;
107 : :
108 : 2 : datafile = NULL;
109 : 2 : datastr = NULL;
110 : 2 : rc = EPKG_FATAL;
111 [ - + ]: 2 : if (STREQ(name, "-")) {
112 : 2 : datafile = stdin; /* XXX Make it configurable? */
113 : 2 : name = "stdin";
114 : 2 : } else {
115 : 0 : datafile = fopen(name, "rb");
116 [ # # ]: 0 : if (datafile == NULL)
117 : 0 : err(EXIT_FAILURE, "fopen");
118 : : }
119 : :
120 : 2 : datastr = xstring_new();
121 [ - + + + ]: 4 : while (!feof(datafile)) {
122 : 2 : readsz = fread(&buf[0], 1, sizeof(buf), datafile);
123 [ + - # # : 2 : if (readsz == 0 && ferror(datafile)) {
# # ]
124 : 0 : fprintf(stderr, "%s: I/O error\n", name);
125 : 0 : goto out;
126 : : }
127 : :
128 : 2 : fwrite(buf, readsz, 1, datastr->fp);
129 : : }
130 : :
131 : 2 : data = xstring_get_binary(datastr, &datasz);
132 : 2 : datastr = NULL;
133 : :
134 : 2 : sig = NULL;
135 : 2 : rc = pkg_key_sign_data(key, (unsigned char *)data, datasz, &sig, &siglen);
136 : 2 : free(data);
137 : :
138 : : #if 0
139 : : fprintf(stderr, "SIGNED: %s\n", data);
140 : : #endif
141 : : /*
142 : : +SIGNED: 64628d55add8b281b9868aea00c4829a3ad260cfc4262e9d1244a1ab67584935
143 : : +SIGNED: a2eb46d60cd26657b273ec55a0909e642ef522f35074a9c62c3c4b42608e55e1
144 : : */
145 : :
146 [ - + ]: 2 : if (rc == EPKG_OK) {
147 : : size_t writesz;
148 : :
149 [ + - ]: 2 : if ((writesz = fwrite(sig, 1, siglen, stdout)) < siglen) {
150 : 0 : fprintf(stderr, "Failed to write signature out [%zu/%zu]\n",
151 : 0 : writesz, siglen);
152 : 0 : rc = EPKG_FATAL;
153 : 0 : }
154 : 2 : }
155 : 2 : free(sig);
156 : :
157 : : out:
158 : 2 : xstring_free(datastr);
159 [ + - ]: 2 : if (datafile != stdin)
160 : 0 : fclose(datafile);
161 : 2 : return rc;
162 : : }
163 : :
164 : : static int
165 : 0 : key_info(struct pkg_key *key, const char *file, const char *type)
166 : : {
167 : : struct iovec *iov;
168 : : int niov, rc;
169 : :
170 : 0 : iov = NULL;
171 : 0 : rc = pkg_key_info(key, &iov, &niov);
172 [ # # ]: 0 : if (rc != EPKG_OK)
173 : 0 : return (rc);
174 : :
175 [ # # ]: 0 : assert((niov % 2) == 0);
176 : :
177 : 0 : printf("Key file '%s' (type %s)\n", file, type);
178 [ # # ]: 0 : for (int i = 0; i < niov; i += 2) {
179 : 0 : const char *kv_name = iov[i].iov_base;
180 : 0 : const char *kv_val = iov[i + 1].iov_base;
181 : 0 : printf(" - %s: %s\n", kv_name, kv_val);
182 : :
183 : 0 : free(iov[i + 1].iov_base);
184 : 0 : }
185 : :
186 : 0 : free(iov);
187 : 0 : return (EPKG_OK);
188 : 0 : }
189 : :
190 : : int
191 : 0 : password_cb(char *buf, int size, int rwflag, void *key)
192 : : {
193 : 0 : int len = 0;
194 : : char pass[BUFSIZ];
195 : : sigset_t sig, oldsig;
196 : :
197 : 0 : (void)rwflag;
198 : 0 : (void)key;
199 : :
200 : : /* Block sigalarm temporary */
201 : 0 : sigemptyset(&sig);
202 : 0 : sigaddset(&sig, SIGALRM);
203 : 0 : sigprocmask(SIG_BLOCK, &sig, &oldsig);
204 : :
205 [ # # ]: 0 : if (readpassphrase("\nEnter passphrase: ", pass, BUFSIZ, RPP_ECHO_OFF) == NULL)
206 : 0 : return 0;
207 : :
208 : 0 : len = strlen(pass);
209 : :
210 [ # # ]: 0 : if (len <= 0) return 0;
211 [ # # ]: 0 : if (len > size) len = size;
212 : :
213 : 0 : memset(buf, '\0', size);
214 : 0 : memcpy(buf, pass, len);
215 : 0 : memset(pass, 0, BUFSIZ);
216 : :
217 : 0 : sigprocmask(SIG_SETMASK, &oldsig, NULL);
218 : :
219 : 0 : return (len);
220 : 0 : }
221 : :
222 : : int
223 : 15 : exec_key(int argc, char **argv)
224 : : {
225 : : int ret;
226 : : int ch;
227 : 15 : struct pkg_key *key = NULL;
228 : 15 : const char *keypath, *keytype = NULL;
229 : : key_mode_t keymode;
230 : :
231 : 15 : struct option longopts[] = {
232 : : { "create", no_argument, NULL, ARG_CREATE },
233 : : { "public", no_argument, NULL, ARG_PUBLIC },
234 : : { "sign", no_argument, NULL, ARG_SIGN },
235 : : { NULL, 0, NULL, 0 },
236 : : };
237 : :
238 : 15 : keymode = MODE_UNSPECIFIED;
239 : :
240 : : /* XXX maybe eventually we can just derive the key type. */
241 [ + + ]: 41 : while ((ch = getopt_long(argc, argv, "t:", longopts, NULL)) != -1) {
242 [ + + + + : 26 : switch (ch) {
- ]
243 : : case ARG_CREATE:
244 [ + - ]: 12 : if (keymode != MODE_UNSPECIFIED) {
245 : 0 : usage_key();
246 : 0 : return (EXIT_FAILURE);
247 : : }
248 : 12 : keymode = MODE_CREATE;
249 : 12 : break;
250 : : case ARG_PUBLIC:
251 [ + - ]: 1 : if (keymode != MODE_UNSPECIFIED) {
252 : 0 : usage_key();
253 : 0 : return (EXIT_FAILURE);
254 : : }
255 : 1 : keymode = MODE_PUBLIC;
256 : 1 : break;
257 : : case ARG_SIGN:
258 [ + - ]: 2 : if (keymode != MODE_UNSPECIFIED) {
259 : 0 : usage_key();
260 : 0 : return (EXIT_FAILURE);
261 : : }
262 : 2 : keymode = MODE_SIGN;
263 : 2 : break;
264 : : case 't':
265 : 11 : keytype = optarg;
266 : 11 : break;
267 : : default:
268 : 0 : usage_key();
269 : 0 : return (EXIT_FAILURE);
270 : : }
271 : : }
272 : 15 : argc -= optind;
273 : 15 : argv += optind;
274 : :
275 [ - + ]: 15 : if (argc != 1) {
276 : 0 : usage_key();
277 : 0 : return (EXIT_FAILURE);
278 : : }
279 : :
280 [ + + ]: 15 : if (keytype == NULL)
281 : 4 : keytype = "rsa";
282 : :
283 : 15 : keypath = argv[0];
284 [ - + ]: 15 : if (*keypath == '\0') {
285 : 0 : fprintf(stderr, "keypath must not be empty.\n");
286 : 0 : usage_key();
287 : 0 : return (EXIT_FAILURE);
288 : : }
289 : :
290 : 15 : ret = pkg_key_new(&key, keytype, keypath, password_cb);
291 [ - + ]: 15 : if (ret != EPKG_OK) {
292 : 0 : fprintf(stderr, "Failed to create key context.\n");
293 : 0 : return (EXIT_FAILURE);
294 : : }
295 : :
296 [ - + + + : 15 : switch (keymode) {
- ]
297 : : case MODE_CREATE:
298 : 12 : ret = key_create(key, argc, argv);
299 [ - + ]: 12 : if (ret != EPKG_OK) {
300 [ # # ]: 0 : switch (ret) {
301 : : case EPKG_OPNOTSUPP:
302 : 0 : fprintf(stderr, "Type '%s' does not support generation.\n",
303 : 0 : keytype);
304 : 0 : break;
305 : : default:
306 : 0 : fprintf(stderr, "Failed to generate the key.\n");
307 : 0 : break;
308 : : }
309 : :
310 : 0 : goto out;
311 : : }
312 : :
313 : 13 : fprintf(stderr, "Created '%s' private key at %s\n", keytype, keypath);
314 : : /* FALLTHROUGH */
315 : : case MODE_PUBLIC:
316 : 13 : ret = key_pubout(key);
317 [ - + ]: 13 : if (ret != EPKG_OK) {
318 [ # # ]: 0 : switch (ret) {
319 : : case EPKG_OPNOTSUPP:
320 : 0 : fprintf(stderr, "Type '%s' does not support pubout.\n",
321 : 0 : keytype);
322 : 0 : break;
323 : : default:
324 : 0 : fprintf(stderr, "Failed to get keyinfo.\n");
325 : 0 : break;
326 : : }
327 : :
328 : 0 : goto out;
329 : : }
330 : :
331 : 13 : break;
332 : : case MODE_SIGN:
333 : 2 : ret = key_sign_data(key, "-");
334 [ - + ]: 2 : if (ret != EPKG_OK) {
335 [ # # ]: 0 : switch (ret) {
336 : : case EPKG_OPNOTSUPP:
337 : 0 : fprintf(stderr, "Type '%s' does not support signing.\n",
338 : 0 : keytype);
339 : 0 : break;
340 : : default:
341 : 0 : fprintf(stderr, "Failed to sign.\n");
342 : 0 : break;
343 : : }
344 : :
345 : 0 : goto out;
346 : : }
347 : 2 : break;
348 : : case MODE_UNSPECIFIED:
349 : 0 : ret = key_info(key, keypath, keytype);
350 [ # # ]: 0 : if (ret != EPKG_OK) {
351 [ # # ]: 0 : switch (ret) {
352 : : case EPKG_OPNOTSUPP:
353 : 0 : printf("Type '%s' does not support keyinfo.\n",
354 : 0 : keytype);
355 : 0 : break;
356 : : default:
357 : 0 : printf("Failed to get keyinfo.\n");
358 : 0 : break;
359 : : }
360 : :
361 : 0 : goto out;
362 : : }
363 : :
364 : 0 : break;
365 : 15 : }
366 : :
367 : : out:
368 : 15 : pkg_key_free(key);
369 : 15 : return (ret == EPKG_OK ? EXIT_SUCCESS : EXIT_FAILURE);
370 : 15 : }
|