Home | History | Annotate | Download | only in dropbear
      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