• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
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. */
24 
25 /* The format of the keyfiles is basically a raw dump of the buffer. Data types
26  * are specified in the transport draft - 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()
29 
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)
37  *
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
45  *
46  */
47 #include "includes.h"
48 #include "signkey.h"
49 #include "buffer.h"
50 #include "dbutil.h"
51 
52 #include "genrsa.h"
53 #include "gendss.h"
54 
55 static void printhelp(char * progname);
56 
57 #define RSA_SIZE (1024/8) /* 1024 bit */
58 #define DSS_SIZE (1024/8) /* 1024 bit */
59 
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);
63 
64 /* Print a help message */
printhelp(char * progname)65 static void printhelp(char * progname) {
66 
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 					"-y		Just print the publickey and fingerprint for the\n		private key in <filename>.\n"
79 #ifdef DEBUG_TRACE
80 					"-v		verbose\n"
81 #endif
82 					,progname);
83 }
84 
85 #if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
86 #if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
dropbearkey_main(int argc,char ** argv)87 int dropbearkey_main(int argc, char ** argv) {
88 #else
89 int main(int argc, char ** argv) {
90 #endif
91 
92 	int i;
93 	char ** next = 0;
94 	sign_key *key = NULL;
95 	buffer *buf = NULL;
96 	char * filename = NULL;
97 	int keytype = -1;
98 	char * typetext = NULL;
99 	char * sizetext = NULL;
100 	unsigned int bits;
101 	unsigned int keysize;
102 	int printpub = 0;
103 
104 	/* get the commandline options */
105 	for (i = 1; i < argc; i++) {
106 		if (argv[i] == NULL) {
107 			continue; /* Whack */
108 		}
109 		if (next) {
110 			*next = argv[i];
111 			next = NULL;
112 			continue;
113 		}
114 
115 		if (argv[i][0] == '-') {
116 			switch (argv[i][1]) {
117 				case 'f':
118 					next = &filename;
119 					break;
120 				case 't':
121 					next = &typetext;
122 					break;
123 				case 's':
124 					next = &sizetext;
125 					break;
126 				case 'y':
127 					printpub = 1;
128 					break;
129 				case 'h':
130 					printhelp(argv[0]);
131 					exit(EXIT_SUCCESS);
132 					break;
133 #ifdef DEBUG_TRACE
134 				case 'v':
135 					debug_trace = 1;
136 					break;
137 #endif
138 				default:
139 					fprintf(stderr, "Unknown argument %s\n", argv[i]);
140 					printhelp(argv[0]);
141 					exit(EXIT_FAILURE);
142 					break;
143 			}
144 		}
145 	}
146 
147 	if (!filename) {
148 		fprintf(stderr, "Must specify a key filename\n");
149 		printhelp(argv[0]);
150 		exit(EXIT_FAILURE);
151 	}
152 
153 	if (printpub) {
154 		justprintpub(filename);
155 		/* Not reached */
156 	}
157 
158 	/* check/parse args */
159 	if (!typetext) {
160 		fprintf(stderr, "Must specify key type\n");
161 		printhelp(argv[0]);
162 		exit(EXIT_FAILURE);
163 	}
164 
165 	if (strlen(typetext) == 3) {
166 #ifdef DROPBEAR_RSA
167 		if (strncmp(typetext, "rsa", 3) == 0) {
168 			keytype = DROPBEAR_SIGNKEY_RSA;
169 			TRACE(("type is rsa"))
170 		}
171 #endif
172 #ifdef DROPBEAR_DSS
173 		if (strncmp(typetext, "dss", 3) == 0) {
174 			keytype = DROPBEAR_SIGNKEY_DSS;
175 			TRACE(("type is dss"))
176 		}
177 #endif
178 	}
179 	if (keytype == -1) {
180 		fprintf(stderr, "Unknown key type '%s'\n", typetext);
181 		printhelp(argv[0]);
182 		exit(EXIT_FAILURE);
183 	}
184 
185 	if (sizetext) {
186 		if (sscanf(sizetext, "%u", &bits) != 1) {
187 			fprintf(stderr, "Bits must be an integer\n");
188 			exit(EXIT_FAILURE);
189 		}
190 
191 		if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
192 			fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
193 					" multiple of 8\n");
194 			exit(EXIT_FAILURE);
195 		}
196 
197 		keysize = bits / 8;
198 	} else {
199 		if (keytype == DROPBEAR_SIGNKEY_DSS) {
200 			keysize = DSS_SIZE;
201 		} else if (keytype == DROPBEAR_SIGNKEY_RSA) {
202 			keysize = RSA_SIZE;
203 		} else {
204 			exit(EXIT_FAILURE); /* not reached */
205 		}
206 	}
207 
208 
209 	fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8,
210 			typetext, filename);
211 
212 	/* don't want the file readable by others */
213 	umask(077);
214 
215 	/* now we can generate the key */
216 	key = new_sign_key();
217 
218 	fprintf(stderr, "Generating key, this may take a while...\n");
219 	switch(keytype) {
220 #ifdef DROPBEAR_RSA
221 		case DROPBEAR_SIGNKEY_RSA:
222 			key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
223 			break;
224 #endif
225 #ifdef DROPBEAR_DSS
226 		case DROPBEAR_SIGNKEY_DSS:
227 			key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
228 			break;
229 #endif
230 		default:
231 			fprintf(stderr, "Internal error, bad key type\n");
232 			exit(EXIT_FAILURE);
233 	}
234 
235 	buf = buf_new(MAX_PRIVKEY_SIZE);
236 
237 	buf_put_priv_key(buf, key, keytype);
238 	buf_setpos(buf, 0);
239 	buf_writefile(buf, filename);
240 
241 	buf_burn(buf);
242 	buf_free(buf);
243 
244 	printpubkey(key, keytype);
245 
246 	sign_key_free(key);
247 
248 	return EXIT_SUCCESS;
249 }
250 #endif
251 
252 static void justprintpub(const char* filename) {
253 
254 	buffer *buf = NULL;
255 	sign_key *key = NULL;
256 	int keytype;
257 	int ret;
258 	int err = DROPBEAR_FAILURE;
259 
260 	buf = buf_new(MAX_PRIVKEY_SIZE);
261 	ret = buf_readfile(buf, filename);
262 
263 	if (ret != DROPBEAR_SUCCESS) {
264 		fprintf(stderr, "Failed reading '%s'\n", filename);
265 		goto out;
266 	}
267 
268 	key = new_sign_key();
269 	keytype = DROPBEAR_SIGNKEY_ANY;
270 
271 	buf_setpos(buf, 0);
272 	ret = buf_get_priv_key(buf, key, &keytype);
273 	if (ret == DROPBEAR_FAILURE) {
274 		fprintf(stderr, "Bad key in '%s'\n", filename);
275 		goto out;
276 	}
277 
278 	printpubkey(key, keytype);
279 
280 	err = DROPBEAR_SUCCESS;
281 
282 out:
283 	buf_burn(buf);
284 	buf_free(buf);
285 	buf = NULL;
286 	if (key) {
287 		sign_key_free(key);
288 		key = NULL;
289 	}
290 	exit(err);
291 }
292 
293 static void printpubkey(sign_key * key, int keytype) {
294 
295 	buffer * buf = NULL;
296 	unsigned char base64key[MAX_PUBKEY_SIZE*2];
297 	unsigned long base64len;
298 	int err;
299 	const char * typestring = NULL;
300 	char *fp = NULL;
301 	int len;
302 	struct passwd * pw = NULL;
303 	char * username = NULL;
304 	char hostname[100];
305 
306 	buf = buf_new(MAX_PUBKEY_SIZE);
307 	buf_put_pub_key(buf, key, keytype);
308 	buf_setpos(buf, 4);
309 
310 	len = buf->len - buf->pos;
311 
312 	base64len = sizeof(base64key);
313 	err = base64_encode(buf_getptr(buf, len), len, base64key, &base64len);
314 
315 	if (err != CRYPT_OK) {
316 		fprintf(stderr, "base64 failed");
317 	}
318 
319 	typestring = signkey_name_from_type(keytype, &err);
320 
321 	fp = sign_key_fingerprint(buf_getptr(buf, len), len);
322 
323 	/* a user@host comment is informative */
324 	username = "";
325 	pw = getpwuid(getuid());
326 	if (pw) {
327 		username = pw->pw_name;
328 	}
329 
330 	gethostname(hostname, sizeof(hostname));
331 	hostname[sizeof(hostname)-1] = '\0';
332 
333 	printf("Public key portion is:\n%s %s %s@%s\nFingerprint: %s\n",
334 			typestring, base64key, username, hostname, fp);
335 
336 	m_free(fp);
337 	buf_free(buf);
338 }
339 
340 /* Write a buffer to a file specified, failing if the file exists */
341 static void buf_writefile(buffer * buf, const char * filename) {
342 
343 	int fd;
344 	int len;
345 
346 	fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
347 	if (fd < 0) {
348 		fprintf(stderr, "Couldn't create new file %s\n", filename);
349 		perror("Reason");
350 		buf_burn(buf);
351 		exit(EXIT_FAILURE);
352 	}
353 
354 	/* write the file now */
355 	while (buf->pos != buf->len) {
356 		len = write(fd, buf_getptr(buf, buf->len - buf->pos),
357 				buf->len - buf->pos);
358 		if (errno == EINTR) {
359 			continue;
360 		}
361 		if (len <= 0) {
362 			fprintf(stderr, "Failed writing file '%s'\n",filename);
363 			perror("Reason");
364 			exit(EXIT_FAILURE);
365 		}
366 		buf_incrpos(buf, len);
367 	}
368 
369 	close(fd);
370 }
371