libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / dropbear / dropbearkey.c
blob421b6e0bf0f048dd4eb6817531594496a386a2e0
1 /*
2 * Dropbear - a SSH2 server
3 *
4 * Copyright (c) 2002,2003 Matt Johnston
5 * All rights reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE. */
25 /* The format of the keyfiles is basically a raw dump of the buffer. Data types
26 * are specified in the transport rfc 4253 - string is a 32-bit len then the
27 * non-null-terminated string, mp_int is a 32-bit len then the bignum data.
28 * The actual functions are buf_put_rsa_priv_key() and buf_put_dss_priv_key()
30 * RSA:
31 * string "ssh-rsa"
32 * mp_int e
33 * mp_int n
34 * mp_int d
35 * mp_int p (newer versions only)
36 * mp_int q (newer versions only)
38 * DSS:
39 * string "ssh-dss"
40 * mp_int p
41 * mp_int q
42 * mp_int g
43 * mp_int y
44 * mp_int x
47 #include "includes.h"
48 #include "signkey.h"
49 #include "buffer.h"
50 #include "dbutil.h"
52 #include "genrsa.h"
53 #include "gendss.h"
55 static void printhelp(char * progname);
57 #define RSA_SIZE (1024/8) /* 1024 bit */
58 #define DSS_SIZE (1024/8) /* 1024 bit */
60 static void buf_writefile(buffer * buf, const char * filename);
61 static void printpubkey(sign_key * key, int keytype);
62 static void justprintpub(const char* filename);
64 /* Print a help message */
65 static void printhelp(char * progname) {
67 fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
68 "Options are:\n"
69 "-t type Type of key to generate. One of:\n"
70 #ifdef DROPBEAR_RSA
71 " rsa\n"
72 #endif
73 #ifdef DROPBEAR_DSS
74 " dss\n"
75 #endif
76 "-f filename Use filename for the secret key\n"
77 "-s bits Key size in bits, should be a multiple of 8 (optional)\n"
78 " (DSS has a fixed size of 1024 bits)\n"
79 "-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
80 #ifdef DEBUG_TRACE
81 "-v verbose\n"
82 #endif
83 ,progname);
86 #if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
87 #if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
88 int dropbearkey_main(int argc, char ** argv) {
89 #else
90 int main(int argc, char ** argv) {
91 #endif
93 int i;
94 char ** next = 0;
95 sign_key *key = NULL;
96 buffer *buf = NULL;
97 char * filename = NULL;
98 int keytype = -1;
99 char * typetext = NULL;
100 char * sizetext = NULL;
101 unsigned int bits;
102 unsigned int keysize;
103 int printpub = 0;
105 /* get the commandline options */
106 for (i = 1; i < argc; i++) {
107 if (argv[i] == NULL) {
108 continue; /* Whack */
110 if (next) {
111 *next = argv[i];
112 next = NULL;
113 continue;
116 if (argv[i][0] == '-') {
117 switch (argv[i][1]) {
118 case 'f':
119 next = &filename;
120 break;
121 case 't':
122 next = &typetext;
123 break;
124 case 's':
125 next = &sizetext;
126 break;
127 case 'y':
128 printpub = 1;
129 break;
130 case 'h':
131 printhelp(argv[0]);
132 exit(EXIT_SUCCESS);
133 break;
134 #ifdef DEBUG_TRACE
135 case 'v':
136 debug_trace = 1;
137 break;
138 #endif
139 default:
140 fprintf(stderr, "Unknown argument %s\n", argv[i]);
141 printhelp(argv[0]);
142 exit(EXIT_FAILURE);
143 break;
148 if (!filename) {
149 fprintf(stderr, "Must specify a key filename\n");
150 printhelp(argv[0]);
151 exit(EXIT_FAILURE);
154 if (printpub) {
155 justprintpub(filename);
156 /* Not reached */
159 /* check/parse args */
160 if (!typetext) {
161 fprintf(stderr, "Must specify key type\n");
162 printhelp(argv[0]);
163 exit(EXIT_FAILURE);
166 if (strlen(typetext) == 3) {
167 #ifdef DROPBEAR_RSA
168 if (strncmp(typetext, "rsa", 3) == 0) {
169 keytype = DROPBEAR_SIGNKEY_RSA;
170 TRACE(("type is rsa"))
172 #endif
173 #ifdef DROPBEAR_DSS
174 if (strncmp(typetext, "dss", 3) == 0) {
175 keytype = DROPBEAR_SIGNKEY_DSS;
176 TRACE(("type is dss"))
178 #endif
180 if (keytype == -1) {
181 fprintf(stderr, "Unknown key type '%s'\n", typetext);
182 printhelp(argv[0]);
183 exit(EXIT_FAILURE);
186 if (sizetext) {
187 if (sscanf(sizetext, "%u", &bits) != 1) {
188 fprintf(stderr, "Bits must be an integer\n");
189 exit(EXIT_FAILURE);
192 if (keytype == DROPBEAR_SIGNKEY_DSS && bits != 1024) {
193 fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
194 exit(EXIT_FAILURE);
195 } else if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
196 fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
197 " multiple of 8\n");
198 exit(EXIT_FAILURE);
201 keysize = bits / 8;
202 } else {
203 if (keytype == DROPBEAR_SIGNKEY_DSS) {
204 keysize = DSS_SIZE;
205 } else if (keytype == DROPBEAR_SIGNKEY_RSA) {
206 keysize = RSA_SIZE;
207 } else {
208 exit(EXIT_FAILURE); /* not reached */
213 fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8,
214 typetext, filename);
216 /* don't want the file readable by others */
217 umask(077);
219 /* now we can generate the key */
220 key = new_sign_key();
222 fprintf(stderr, "Generating key, this may take a while...\n");
223 switch(keytype) {
224 #ifdef DROPBEAR_RSA
225 case DROPBEAR_SIGNKEY_RSA:
226 key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
227 break;
228 #endif
229 #ifdef DROPBEAR_DSS
230 case DROPBEAR_SIGNKEY_DSS:
231 key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
232 break;
233 #endif
234 default:
235 fprintf(stderr, "Internal error, bad key type\n");
236 exit(EXIT_FAILURE);
239 buf = buf_new(MAX_PRIVKEY_SIZE);
241 buf_put_priv_key(buf, key, keytype);
242 buf_setpos(buf, 0);
243 buf_writefile(buf, filename);
245 buf_burn(buf);
246 buf_free(buf);
248 printpubkey(key, keytype);
250 sign_key_free(key);
252 return EXIT_SUCCESS;
254 #endif
256 static void justprintpub(const char* filename) {
258 buffer *buf = NULL;
259 sign_key *key = NULL;
260 int keytype;
261 int ret;
262 int err = DROPBEAR_FAILURE;
264 buf = buf_new(MAX_PRIVKEY_SIZE);
265 ret = buf_readfile(buf, filename);
267 if (ret != DROPBEAR_SUCCESS) {
268 fprintf(stderr, "Failed reading '%s'\n", filename);
269 goto out;
272 key = new_sign_key();
273 keytype = DROPBEAR_SIGNKEY_ANY;
275 buf_setpos(buf, 0);
276 ret = buf_get_priv_key(buf, key, &keytype);
277 if (ret == DROPBEAR_FAILURE) {
278 fprintf(stderr, "Bad key in '%s'\n", filename);
279 goto out;
282 printpubkey(key, keytype);
284 err = DROPBEAR_SUCCESS;
286 out:
287 buf_burn(buf);
288 buf_free(buf);
289 buf = NULL;
290 if (key) {
291 sign_key_free(key);
292 key = NULL;
294 exit(err);
297 static void printpubkey(sign_key * key, int keytype) {
299 buffer * buf = NULL;
300 unsigned char base64key[MAX_PUBKEY_SIZE*2];
301 unsigned long base64len;
302 int err;
303 const char * typestring = NULL;
304 char *fp = NULL;
305 int len;
306 struct passwd * pw = NULL;
307 char * username = NULL;
308 char hostname[100];
310 buf = buf_new(MAX_PUBKEY_SIZE);
311 buf_put_pub_key(buf, key, keytype);
312 buf_setpos(buf, 4);
314 len = buf->len - buf->pos;
316 base64len = sizeof(base64key);
317 err = base64_encode(buf_getptr(buf, len), len, base64key, &base64len);
319 if (err != CRYPT_OK) {
320 fprintf(stderr, "base64 failed");
323 typestring = signkey_name_from_type(keytype, &err);
325 fp = sign_key_fingerprint(buf_getptr(buf, len), len);
327 /* a user@host comment is informative */
328 username = "";
329 pw = getpwuid(getuid());
330 if (pw) {
331 username = pw->pw_name;
334 gethostname(hostname, sizeof(hostname));
335 hostname[sizeof(hostname)-1] = '\0';
337 printf("Public key portion is:\n%s %s %s@%s\nFingerprint: %s\n",
338 typestring, base64key, username, hostname, fp);
340 m_free(fp);
341 buf_free(buf);
344 /* Write a buffer to a file specified, failing if the file exists */
345 static void buf_writefile(buffer * buf, const char * filename) {
347 int fd;
348 int len;
350 fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
351 if (fd < 0) {
352 fprintf(stderr, "Couldn't create new file %s\n", filename);
353 perror("Reason");
354 buf_burn(buf);
355 exit(EXIT_FAILURE);
358 /* write the file now */
359 while (buf->pos != buf->len) {
360 len = write(fd, buf_getptr(buf, buf->len - buf->pos),
361 buf->len - buf->pos);
362 if (errno == EINTR) {
363 continue;
365 if (len <= 0) {
366 fprintf(stderr, "Failed writing file '%s'\n",filename);
367 perror("Reason");
368 exit(EXIT_FAILURE);
370 buf_incrpos(buf, len);
373 close(fd);