Mercurial > dropbear
comparison dropbearkey.c @ 391:00fcf5045160
propagate from branch 'au.asn.ucc.matt.ltc.dropbear' (head c1db4398d56c56c6d06ae1e20c1e0d04dbb598ed)
to branch 'au.asn.ucc.matt.dropbear' (head d26d5eb2837f46b56a33fb0e7573aa0201abd4d5)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 11 Jan 2007 04:29:08 +0000 |
parents | 454a34b2dfd1 |
children | e430a26064ee |
comparison
equal
deleted
inserted
replaced
390:d8e44bef7917 | 391:00fcf5045160 |
---|---|
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 */ | |
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) | |
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 } |