Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/src/key.c
2648 views
1
/*-
2
* Copyright (c) 2021 Kyle Evans <[email protected]>
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
#include <sys/uio.h>
27
28
#include <bsd_compat.h>
29
#include <assert.h>
30
#include <err.h>
31
#include <getopt.h>
32
#include <signal.h>
33
#include <stdio.h>
34
#include <string.h>
35
36
#if __has_include(<readpassphrase.h>)
37
#include <readpassphrase.h>
38
#elif __has_include(<bsd/readpassphrase.h>)
39
#include <bsd/readpassphrase.h>
40
#else
41
#include "readpassphrase_compat.h"
42
#endif
43
44
#include <unistd.h>
45
46
#include <pkg.h>
47
#include "pkgcli.h"
48
49
enum {
50
ARG_CREATE = CHAR_MAX + 1,
51
ARG_PUBLIC,
52
ARG_SIGN,
53
};
54
55
typedef enum {
56
MODE_UNSPECIFIED = 0,
57
MODE_CREATE,
58
MODE_PUBLIC,
59
MODE_SIGN,
60
} key_mode_t;
61
62
void
63
usage_key(void)
64
{
65
fprintf(stderr, "Usage: pkg key [--create | --public | --sign] [-t <type>] "
66
"<key-path>\n");
67
fprintf(stderr, "For more information see 'pkg help key'.\n");
68
}
69
70
static int
71
key_create(struct pkg_key *key, int argc __unused, char *argv[] __unused)
72
{
73
/* No arguments to setup for now. */
74
return (pkg_key_create(key, NULL, 0));
75
}
76
77
static int
78
key_pubout(struct pkg_key *key)
79
{
80
char *keybuf = NULL;
81
size_t keylen;
82
int ret;
83
84
ret = pkg_key_pubkey(key, &keybuf, &keylen);
85
if (ret != EPKG_OK)
86
return (ret);
87
88
fwrite(keybuf, keylen, 1, stdout);
89
free(keybuf);
90
return (0);
91
}
92
93
static int
94
key_sign_data(struct pkg_key *key, const char *name)
95
{
96
char buf[BUFSIZ];
97
xstring *datastr;
98
char *data;
99
unsigned char *sig;
100
size_t datasz, readsz, siglen;
101
FILE *datafile;
102
int rc;
103
104
datafile = NULL;
105
datastr = NULL;
106
rc = EPKG_FATAL;
107
if (STREQ(name, "-")) {
108
datafile = stdin; /* XXX Make it configurable? */
109
name = "stdin";
110
} else {
111
datafile = fopen(name, "rb");
112
if (datafile == NULL)
113
err(EXIT_FAILURE, "fopen");
114
}
115
116
datastr = xstring_new();
117
while (!feof(datafile)) {
118
readsz = fread(&buf[0], 1, sizeof(buf), datafile);
119
if (readsz == 0 && ferror(datafile)) {
120
fprintf(stderr, "%s: I/O error\n", name);
121
goto out;
122
}
123
124
fwrite(buf, readsz, 1, datastr->fp);
125
}
126
127
data = xstring_get_binary(datastr, &datasz);
128
datastr = NULL;
129
130
sig = NULL;
131
rc = pkg_key_sign_data(key, (unsigned char *)data, datasz, &sig, &siglen);
132
free(data);
133
134
#if 0
135
fprintf(stderr, "SIGNED: %s\n", data);
136
#endif
137
/*
138
+SIGNED: 64628d55add8b281b9868aea00c4829a3ad260cfc4262e9d1244a1ab67584935
139
+SIGNED: a2eb46d60cd26657b273ec55a0909e642ef522f35074a9c62c3c4b42608e55e1
140
*/
141
142
if (rc == EPKG_OK) {
143
size_t writesz;
144
145
if ((writesz = fwrite(sig, 1, siglen, stdout)) < siglen) {
146
fprintf(stderr, "Failed to write signature out [%zu/%zu]\n",
147
writesz, siglen);
148
rc = EPKG_FATAL;
149
}
150
}
151
free(sig);
152
153
out:
154
xstring_free(datastr);
155
if (datafile != stdin)
156
fclose(datafile);
157
return rc;
158
}
159
160
static int
161
key_info(struct pkg_key *key, const char *file, const char *type)
162
{
163
struct iovec *iov;
164
int niov, rc;
165
166
iov = NULL;
167
rc = pkg_key_info(key, &iov, &niov);
168
if (rc != EPKG_OK)
169
return (rc);
170
171
assert((niov % 2) == 0);
172
173
printf("Key file '%s' (type %s)\n", file, type);
174
for (int i = 0; i < niov; i += 2) {
175
const char *kv_name = iov[i].iov_base;
176
const char *kv_val = iov[i + 1].iov_base;
177
printf(" - %s: %s\n", kv_name, kv_val);
178
179
free(iov[i + 1].iov_base);
180
}
181
182
free(iov);
183
return (EPKG_OK);
184
}
185
186
int
187
password_cb(char *buf, int size, int rwflag, void *key)
188
{
189
int len = 0;
190
char pass[BUFSIZ];
191
sigset_t sig, oldsig;
192
193
(void)rwflag;
194
(void)key;
195
196
/* Block sigalarm temporary */
197
sigemptyset(&sig);
198
sigaddset(&sig, SIGALRM);
199
sigprocmask(SIG_BLOCK, &sig, &oldsig);
200
201
if (readpassphrase("\nEnter passphrase: ", pass, BUFSIZ, RPP_ECHO_OFF) == NULL)
202
return 0;
203
204
len = strlen(pass);
205
206
if (len <= 0) return 0;
207
if (len > size) len = size;
208
209
memset(buf, '\0', size);
210
memcpy(buf, pass, len);
211
memset(pass, 0, BUFSIZ);
212
213
sigprocmask(SIG_SETMASK, &oldsig, NULL);
214
215
return (len);
216
}
217
218
int
219
exec_key(int argc, char **argv)
220
{
221
int ret;
222
int ch;
223
struct pkg_key *key = NULL;
224
const char *keypath, *keytype = NULL;
225
key_mode_t keymode;
226
227
struct option longopts[] = {
228
{ "create", no_argument, NULL, ARG_CREATE },
229
{ "public", no_argument, NULL, ARG_PUBLIC },
230
{ "sign", no_argument, NULL, ARG_SIGN },
231
{ NULL, 0, NULL, 0 },
232
};
233
234
keymode = MODE_UNSPECIFIED;
235
236
/* XXX maybe eventually we can just derive the key type. */
237
while ((ch = getopt_long(argc, argv, "t:", longopts, NULL)) != -1) {
238
switch (ch) {
239
case ARG_CREATE:
240
if (keymode != MODE_UNSPECIFIED) {
241
usage_key();
242
return (EXIT_FAILURE);
243
}
244
keymode = MODE_CREATE;
245
break;
246
case ARG_PUBLIC:
247
if (keymode != MODE_UNSPECIFIED) {
248
usage_key();
249
return (EXIT_FAILURE);
250
}
251
keymode = MODE_PUBLIC;
252
break;
253
case ARG_SIGN:
254
if (keymode != MODE_UNSPECIFIED) {
255
usage_key();
256
return (EXIT_FAILURE);
257
}
258
keymode = MODE_SIGN;
259
break;
260
case 't':
261
keytype = optarg;
262
break;
263
default:
264
usage_key();
265
return (EXIT_FAILURE);
266
}
267
}
268
argc -= optind;
269
argv += optind;
270
271
if (argc != 1) {
272
usage_key();
273
return (EXIT_FAILURE);
274
}
275
276
if (keytype == NULL)
277
keytype = "rsa";
278
279
keypath = argv[0];
280
if (*keypath == '\0') {
281
fprintf(stderr, "keypath must not be empty.\n");
282
usage_key();
283
return (EXIT_FAILURE);
284
}
285
286
ret = pkg_key_new(&key, keytype, keypath, password_cb);
287
if (ret != EPKG_OK) {
288
fprintf(stderr, "Failed to create key context.\n");
289
return (EXIT_FAILURE);
290
}
291
292
switch (keymode) {
293
case MODE_CREATE:
294
ret = key_create(key, argc, argv);
295
if (ret != EPKG_OK) {
296
switch (ret) {
297
case EPKG_OPNOTSUPP:
298
fprintf(stderr, "Type '%s' does not support generation.\n",
299
keytype);
300
break;
301
default:
302
fprintf(stderr, "Failed to generate the key.\n");
303
break;
304
}
305
306
goto out;
307
}
308
309
fprintf(stderr, "Created '%s' private key at %s\n", keytype, keypath);
310
/* FALLTHROUGH */
311
case MODE_PUBLIC:
312
ret = key_pubout(key);
313
if (ret != EPKG_OK) {
314
switch (ret) {
315
case EPKG_OPNOTSUPP:
316
fprintf(stderr, "Type '%s' does not support pubout.\n",
317
keytype);
318
break;
319
default:
320
fprintf(stderr, "Failed to get keyinfo.\n");
321
break;
322
}
323
324
goto out;
325
}
326
327
break;
328
case MODE_SIGN:
329
ret = key_sign_data(key, "-");
330
if (ret != EPKG_OK) {
331
switch (ret) {
332
case EPKG_OPNOTSUPP:
333
fprintf(stderr, "Type '%s' does not support signing.\n",
334
keytype);
335
break;
336
default:
337
fprintf(stderr, "Failed to sign.\n");
338
break;
339
}
340
341
goto out;
342
}
343
break;
344
case MODE_UNSPECIFIED:
345
ret = key_info(key, keypath, keytype);
346
if (ret != EPKG_OK) {
347
switch (ret) {
348
case EPKG_OPNOTSUPP:
349
printf("Type '%s' does not support keyinfo.\n",
350
keytype);
351
break;
352
default:
353
printf("Failed to get keyinfo.\n");
354
break;
355
}
356
357
goto out;
358
}
359
360
break;
361
}
362
363
out:
364
pkg_key_free(key);
365
return (ret == EPKG_OK ? EXIT_SUCCESS : EXIT_FAILURE);
366
}
367
368