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 } 371