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