diff options
Diffstat (limited to 'authfile.c')
-rw-r--r-- | authfile.c | 474 |
1 files changed, 283 insertions, 191 deletions
diff --git a/authfile.c b/authfile.c index e748ec0a2..be650af67 100644 --- a/authfile.c +++ b/authfile.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfile.c,v 1.82 2010/08/04 05:49:22 djm Exp $ */ | 1 | /* $OpenBSD: authfile.c,v 1.87 2010/11/29 18:57:04 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -75,19 +75,18 @@ static const char authfile_id_string[] = | |||
75 | "SSH PRIVATE KEY FILE FORMAT 1.1\n"; | 75 | "SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
76 | 76 | ||
77 | /* | 77 | /* |
78 | * Saves the authentication (private) key in a file, encrypting it with | 78 | * Serialises the authentication (private) key to a blob, encrypting it with |
79 | * passphrase. The identification of the file (lowest 64 bits of n) will | 79 | * passphrase. The identification of the blob (lowest 64 bits of n) will |
80 | * precede the key to provide identification of the key without needing a | 80 | * precede the key to provide identification of the key without needing a |
81 | * passphrase. | 81 | * passphrase. |
82 | */ | 82 | */ |
83 | |||
84 | static int | 83 | static int |
85 | key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, | 84 | key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, |
86 | const char *comment) | 85 | const char *comment) |
87 | { | 86 | { |
88 | Buffer buffer, encrypted; | 87 | Buffer buffer, encrypted; |
89 | u_char buf[100], *cp; | 88 | u_char buf[100], *cp; |
90 | int fd, i, cipher_num; | 89 | int i, cipher_num; |
91 | CipherContext ciphercontext; | 90 | CipherContext ciphercontext; |
92 | Cipher *cipher; | 91 | Cipher *cipher; |
93 | u_int32_t rnd; | 92 | u_int32_t rnd; |
@@ -158,156 +157,222 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, | |||
158 | memset(buf, 0, sizeof(buf)); | 157 | memset(buf, 0, sizeof(buf)); |
159 | buffer_free(&buffer); | 158 | buffer_free(&buffer); |
160 | 159 | ||
161 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); | 160 | buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); |
162 | if (fd < 0) { | ||
163 | error("open %s failed: %s.", filename, strerror(errno)); | ||
164 | buffer_free(&encrypted); | ||
165 | return 0; | ||
166 | } | ||
167 | if (atomicio(vwrite, fd, buffer_ptr(&encrypted), | ||
168 | buffer_len(&encrypted)) != buffer_len(&encrypted)) { | ||
169 | error("write to key file %s failed: %s", filename, | ||
170 | strerror(errno)); | ||
171 | buffer_free(&encrypted); | ||
172 | close(fd); | ||
173 | unlink(filename); | ||
174 | return 0; | ||
175 | } | ||
176 | close(fd); | ||
177 | buffer_free(&encrypted); | 161 | buffer_free(&encrypted); |
162 | |||
178 | return 1; | 163 | return 1; |
179 | } | 164 | } |
180 | 165 | ||
181 | /* save SSH v2 key in OpenSSL PEM format */ | 166 | /* convert SSH v2 key in OpenSSL PEM format */ |
182 | static int | 167 | static int |
183 | key_save_private_pem(Key *key, const char *filename, const char *_passphrase, | 168 | key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, |
184 | const char *comment) | 169 | const char *comment) |
185 | { | 170 | { |
186 | FILE *fp; | ||
187 | int fd; | ||
188 | int success = 0; | 171 | int success = 0; |
189 | int len = strlen(_passphrase); | 172 | int blen, len = strlen(_passphrase); |
190 | u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; | 173 | u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; |
191 | #if (OPENSSL_VERSION_NUMBER < 0x00907000L) | 174 | #if (OPENSSL_VERSION_NUMBER < 0x00907000L) |
192 | const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; | 175 | const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; |
193 | #else | 176 | #else |
194 | const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; | 177 | const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; |
195 | #endif | 178 | #endif |
179 | const u_char *bptr; | ||
180 | BIO *bio; | ||
196 | 181 | ||
197 | if (len > 0 && len <= 4) { | 182 | if (len > 0 && len <= 4) { |
198 | error("passphrase too short: have %d bytes, need > 4", len); | 183 | error("passphrase too short: have %d bytes, need > 4", len); |
199 | return 0; | 184 | return 0; |
200 | } | 185 | } |
201 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); | 186 | if ((bio = BIO_new(BIO_s_mem())) == NULL) { |
202 | if (fd < 0) { | 187 | error("%s: BIO_new failed", __func__); |
203 | error("open %s failed: %s.", filename, strerror(errno)); | ||
204 | return 0; | ||
205 | } | ||
206 | fp = fdopen(fd, "w"); | ||
207 | if (fp == NULL) { | ||
208 | error("fdopen %s failed: %s.", filename, strerror(errno)); | ||
209 | close(fd); | ||
210 | return 0; | 188 | return 0; |
211 | } | 189 | } |
212 | switch (key->type) { | 190 | switch (key->type) { |
213 | case KEY_DSA: | 191 | case KEY_DSA: |
214 | success = PEM_write_DSAPrivateKey(fp, key->dsa, | 192 | success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, |
215 | cipher, passphrase, len, NULL, NULL); | 193 | cipher, passphrase, len, NULL, NULL); |
216 | break; | 194 | break; |
195 | #ifdef OPENSSL_HAS_ECC | ||
196 | case KEY_ECDSA: | ||
197 | success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, | ||
198 | cipher, passphrase, len, NULL, NULL); | ||
199 | break; | ||
200 | #endif | ||
217 | case KEY_RSA: | 201 | case KEY_RSA: |
218 | success = PEM_write_RSAPrivateKey(fp, key->rsa, | 202 | success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, |
219 | cipher, passphrase, len, NULL, NULL); | 203 | cipher, passphrase, len, NULL, NULL); |
220 | break; | 204 | break; |
221 | } | 205 | } |
222 | fclose(fp); | 206 | if (success) { |
207 | if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) | ||
208 | success = 0; | ||
209 | else | ||
210 | buffer_append(blob, bptr, blen); | ||
211 | } | ||
212 | BIO_free(bio); | ||
223 | return success; | 213 | return success; |
224 | } | 214 | } |
225 | 215 | ||
226 | int | 216 | /* Save a key blob to a file */ |
227 | key_save_private(Key *key, const char *filename, const char *passphrase, | 217 | static int |
218 | key_save_private_blob(Buffer *keybuf, const char *filename) | ||
219 | { | ||
220 | int fd; | ||
221 | |||
222 | if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { | ||
223 | error("open %s failed: %s.", filename, strerror(errno)); | ||
224 | return 0; | ||
225 | } | ||
226 | if (atomicio(vwrite, fd, buffer_ptr(keybuf), | ||
227 | buffer_len(keybuf)) != buffer_len(keybuf)) { | ||
228 | error("write to key file %s failed: %s", filename, | ||
229 | strerror(errno)); | ||
230 | close(fd); | ||
231 | unlink(filename); | ||
232 | return 0; | ||
233 | } | ||
234 | close(fd); | ||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | /* Serialise "key" to buffer "blob" */ | ||
239 | static int | ||
240 | key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, | ||
228 | const char *comment) | 241 | const char *comment) |
229 | { | 242 | { |
230 | switch (key->type) { | 243 | switch (key->type) { |
231 | case KEY_RSA1: | 244 | case KEY_RSA1: |
232 | return key_save_private_rsa1(key, filename, passphrase, | 245 | return key_private_rsa1_to_blob(key, blob, passphrase, comment); |
233 | comment); | ||
234 | case KEY_DSA: | 246 | case KEY_DSA: |
247 | case KEY_ECDSA: | ||
235 | case KEY_RSA: | 248 | case KEY_RSA: |
236 | return key_save_private_pem(key, filename, passphrase, | 249 | return key_private_pem_to_blob(key, blob, passphrase, comment); |
237 | comment); | ||
238 | default: | 250 | default: |
239 | break; | 251 | error("%s: cannot save key type %d", __func__, key->type); |
252 | return 0; | ||
240 | } | 253 | } |
241 | error("key_save_private: cannot save key type %d", key->type); | 254 | } |
242 | return 0; | 255 | |
256 | int | ||
257 | key_save_private(Key *key, const char *filename, const char *passphrase, | ||
258 | const char *comment) | ||
259 | { | ||
260 | Buffer keyblob; | ||
261 | int success = 0; | ||
262 | |||
263 | buffer_init(&keyblob); | ||
264 | if (!key_private_to_blob(key, &keyblob, passphrase, comment)) | ||
265 | goto out; | ||
266 | if (!key_save_private_blob(&keyblob, filename)) | ||
267 | goto out; | ||
268 | success = 1; | ||
269 | out: | ||
270 | buffer_free(&keyblob); | ||
271 | return success; | ||
243 | } | 272 | } |
244 | 273 | ||
245 | /* | 274 | /* |
246 | * Loads the public part of the ssh v1 key file. Returns NULL if an error was | 275 | * Parse the public, unencrypted portion of a RSA1 key. |
247 | * encountered (the file does not exist or is not readable), and the key | ||
248 | * otherwise. | ||
249 | */ | 276 | */ |
250 | |||
251 | static Key * | 277 | static Key * |
252 | key_load_public_rsa1(int fd, const char *filename, char **commentp) | 278 | key_parse_public_rsa1(Buffer *blob, char **commentp) |
253 | { | 279 | { |
254 | Buffer buffer; | ||
255 | Key *pub; | 280 | Key *pub; |
256 | struct stat st; | 281 | |
257 | char *cp; | 282 | /* Check that it is at least big enough to contain the ID string. */ |
258 | u_int i; | 283 | if (buffer_len(blob) < sizeof(authfile_id_string)) { |
284 | debug3("Truncated RSA1 identifier"); | ||
285 | return NULL; | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * Make sure it begins with the id string. Consume the id string | ||
290 | * from the buffer. | ||
291 | */ | ||
292 | if (memcmp(buffer_ptr(blob), authfile_id_string, | ||
293 | sizeof(authfile_id_string)) != 0) { | ||
294 | debug3("Incorrect RSA1 identifier"); | ||
295 | return NULL; | ||
296 | } | ||
297 | buffer_consume(blob, sizeof(authfile_id_string)); | ||
298 | |||
299 | /* Skip cipher type and reserved data. */ | ||
300 | (void) buffer_get_char(blob); /* cipher type */ | ||
301 | (void) buffer_get_int(blob); /* reserved */ | ||
302 | |||
303 | /* Read the public key from the buffer. */ | ||
304 | (void) buffer_get_int(blob); | ||
305 | pub = key_new(KEY_RSA1); | ||
306 | buffer_get_bignum(blob, pub->rsa->n); | ||
307 | buffer_get_bignum(blob, pub->rsa->e); | ||
308 | if (commentp) | ||
309 | *commentp = buffer_get_string(blob, NULL); | ||
310 | /* The encrypted private part is not parsed by this function. */ | ||
311 | buffer_clear(blob); | ||
312 | |||
313 | return pub; | ||
314 | } | ||
315 | |||
316 | /* Load the contents of a key file into a buffer */ | ||
317 | static int | ||
318 | key_load_file(int fd, const char *filename, Buffer *blob) | ||
319 | { | ||
259 | size_t len; | 320 | size_t len; |
321 | u_char *cp; | ||
322 | struct stat st; | ||
260 | 323 | ||
261 | if (fstat(fd, &st) < 0) { | 324 | if (fstat(fd, &st) < 0) { |
262 | error("fstat for key file %.200s failed: %.100s", | 325 | error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, |
263 | filename, strerror(errno)); | 326 | filename == NULL ? "" : filename, |
264 | return NULL; | 327 | filename == NULL ? "" : " ", |
328 | strerror(errno)); | ||
329 | close(fd); | ||
330 | return 0; | ||
265 | } | 331 | } |
266 | if (st.st_size > 1*1024*1024) { | 332 | if (st.st_size > 1*1024*1024) { |
267 | error("key file %.200s too large", filename); | 333 | error("%s: key file %.200s%stoo large", __func__, |
268 | return NULL; | 334 | filename == NULL ? "" : filename, |
335 | filename == NULL ? "" : " "); | ||
336 | close(fd); | ||
337 | return 0; | ||
269 | } | 338 | } |
270 | len = (size_t)st.st_size; /* truncated */ | 339 | len = (size_t)st.st_size; /* truncated */ |
271 | 340 | ||
272 | buffer_init(&buffer); | 341 | buffer_init(blob); |
273 | cp = buffer_append_space(&buffer, len); | 342 | cp = buffer_append_space(blob, len); |
274 | 343 | ||
275 | if (atomicio(read, fd, cp, len) != len) { | 344 | if (atomicio(read, fd, cp, len) != len) { |
276 | debug("Read from key file %.200s failed: %.100s", filename, | 345 | debug("%s: read from key file %.200s%sfailed: %.100s", __func__, |
346 | filename == NULL ? "" : filename, | ||
347 | filename == NULL ? "" : " ", | ||
277 | strerror(errno)); | 348 | strerror(errno)); |
278 | buffer_free(&buffer); | 349 | buffer_clear(blob); |
279 | return NULL; | 350 | close(fd); |
351 | return 0; | ||
280 | } | 352 | } |
353 | return 1; | ||
354 | } | ||
281 | 355 | ||
282 | /* Check that it is at least big enough to contain the ID string. */ | 356 | /* |
283 | if (len < sizeof(authfile_id_string)) { | 357 | * Loads the public part of the ssh v1 key file. Returns NULL if an error was |
284 | debug3("Not a RSA1 key file %.200s.", filename); | 358 | * encountered (the file does not exist or is not readable), and the key |
359 | * otherwise. | ||
360 | */ | ||
361 | static Key * | ||
362 | key_load_public_rsa1(int fd, const char *filename, char **commentp) | ||
363 | { | ||
364 | Buffer buffer; | ||
365 | Key *pub; | ||
366 | |||
367 | buffer_init(&buffer); | ||
368 | if (!key_load_file(fd, filename, &buffer)) { | ||
285 | buffer_free(&buffer); | 369 | buffer_free(&buffer); |
286 | return NULL; | 370 | return NULL; |
287 | } | 371 | } |
288 | /* | ||
289 | * Make sure it begins with the id string. Consume the id string | ||
290 | * from the buffer. | ||
291 | */ | ||
292 | for (i = 0; i < sizeof(authfile_id_string); i++) | ||
293 | if (buffer_get_char(&buffer) != authfile_id_string[i]) { | ||
294 | debug3("Not a RSA1 key file %.200s.", filename); | ||
295 | buffer_free(&buffer); | ||
296 | return NULL; | ||
297 | } | ||
298 | /* Skip cipher type and reserved data. */ | ||
299 | (void) buffer_get_char(&buffer); /* cipher type */ | ||
300 | (void) buffer_get_int(&buffer); /* reserved */ | ||
301 | |||
302 | /* Read the public key from the buffer. */ | ||
303 | (void) buffer_get_int(&buffer); | ||
304 | pub = key_new(KEY_RSA1); | ||
305 | buffer_get_bignum(&buffer, pub->rsa->n); | ||
306 | buffer_get_bignum(&buffer, pub->rsa->e); | ||
307 | if (commentp) | ||
308 | *commentp = buffer_get_string(&buffer, NULL); | ||
309 | /* The encrypted private part is not parsed by this function. */ | ||
310 | 372 | ||
373 | pub = key_parse_public_rsa1(&buffer, commentp); | ||
374 | if (pub == NULL) | ||
375 | debug3("Could not load \"%s\" as a RSA1 public key", filename); | ||
311 | buffer_free(&buffer); | 376 | buffer_free(&buffer); |
312 | return pub; | 377 | return pub; |
313 | } | 378 | } |
@@ -330,113 +395,73 @@ key_load_public_type(int type, const char *filename, char **commentp) | |||
330 | return NULL; | 395 | return NULL; |
331 | } | 396 | } |
332 | 397 | ||
333 | /* | ||
334 | * Loads the private key from the file. Returns 0 if an error is encountered | ||
335 | * (file does not exist or is not readable, or passphrase is bad). This | ||
336 | * initializes the private key. | ||
337 | * Assumes we are called under uid of the owner of the file. | ||
338 | */ | ||
339 | |||
340 | static Key * | 398 | static Key * |
341 | key_load_private_rsa1(int fd, const char *filename, const char *passphrase, | 399 | key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) |
342 | char **commentp) | ||
343 | { | 400 | { |
344 | u_int i; | ||
345 | int check1, check2, cipher_type; | 401 | int check1, check2, cipher_type; |
346 | size_t len; | 402 | Buffer decrypted; |
347 | Buffer buffer, decrypted; | ||
348 | u_char *cp; | 403 | u_char *cp; |
349 | CipherContext ciphercontext; | 404 | CipherContext ciphercontext; |
350 | Cipher *cipher; | 405 | Cipher *cipher; |
351 | Key *prv = NULL; | 406 | Key *prv = NULL; |
352 | struct stat st; | ||
353 | |||
354 | if (fstat(fd, &st) < 0) { | ||
355 | error("fstat for key file %.200s failed: %.100s", | ||
356 | filename, strerror(errno)); | ||
357 | close(fd); | ||
358 | return NULL; | ||
359 | } | ||
360 | if (st.st_size > 1*1024*1024) { | ||
361 | error("key file %.200s too large", filename); | ||
362 | close(fd); | ||
363 | return (NULL); | ||
364 | } | ||
365 | len = (size_t)st.st_size; /* truncated */ | ||
366 | |||
367 | buffer_init(&buffer); | ||
368 | cp = buffer_append_space(&buffer, len); | ||
369 | |||
370 | if (atomicio(read, fd, cp, len) != len) { | ||
371 | debug("Read from key file %.200s failed: %.100s", filename, | ||
372 | strerror(errno)); | ||
373 | buffer_free(&buffer); | ||
374 | close(fd); | ||
375 | return NULL; | ||
376 | } | ||
377 | 407 | ||
378 | /* Check that it is at least big enough to contain the ID string. */ | 408 | /* Check that it is at least big enough to contain the ID string. */ |
379 | if (len < sizeof(authfile_id_string)) { | 409 | if (buffer_len(blob) < sizeof(authfile_id_string)) { |
380 | debug3("Not a RSA1 key file %.200s.", filename); | 410 | debug3("Truncated RSA1 identifier"); |
381 | buffer_free(&buffer); | ||
382 | close(fd); | ||
383 | return NULL; | 411 | return NULL; |
384 | } | 412 | } |
413 | |||
385 | /* | 414 | /* |
386 | * Make sure it begins with the id string. Consume the id string | 415 | * Make sure it begins with the id string. Consume the id string |
387 | * from the buffer. | 416 | * from the buffer. |
388 | */ | 417 | */ |
389 | for (i = 0; i < sizeof(authfile_id_string); i++) | 418 | if (memcmp(buffer_ptr(blob), authfile_id_string, |
390 | if (buffer_get_char(&buffer) != authfile_id_string[i]) { | 419 | sizeof(authfile_id_string)) != 0) { |
391 | debug3("Not a RSA1 key file %.200s.", filename); | 420 | debug3("Incorrect RSA1 identifier"); |
392 | buffer_free(&buffer); | 421 | return NULL; |
393 | close(fd); | 422 | } |
394 | return NULL; | 423 | buffer_consume(blob, sizeof(authfile_id_string)); |
395 | } | ||
396 | 424 | ||
397 | /* Read cipher type. */ | 425 | /* Read cipher type. */ |
398 | cipher_type = buffer_get_char(&buffer); | 426 | cipher_type = buffer_get_char(blob); |
399 | (void) buffer_get_int(&buffer); /* Reserved data. */ | 427 | (void) buffer_get_int(blob); /* Reserved data. */ |
400 | 428 | ||
401 | /* Read the public key from the buffer. */ | 429 | /* Read the public key from the buffer. */ |
402 | (void) buffer_get_int(&buffer); | 430 | (void) buffer_get_int(blob); |
403 | prv = key_new_private(KEY_RSA1); | 431 | prv = key_new_private(KEY_RSA1); |
404 | 432 | ||
405 | buffer_get_bignum(&buffer, prv->rsa->n); | 433 | buffer_get_bignum(blob, prv->rsa->n); |
406 | buffer_get_bignum(&buffer, prv->rsa->e); | 434 | buffer_get_bignum(blob, prv->rsa->e); |
407 | if (commentp) | 435 | if (commentp) |
408 | *commentp = buffer_get_string(&buffer, NULL); | 436 | *commentp = buffer_get_string(blob, NULL); |
409 | else | 437 | else |
410 | xfree(buffer_get_string(&buffer, NULL)); | 438 | (void)buffer_get_string_ptr(blob, NULL); |
411 | 439 | ||
412 | /* Check that it is a supported cipher. */ | 440 | /* Check that it is a supported cipher. */ |
413 | cipher = cipher_by_number(cipher_type); | 441 | cipher = cipher_by_number(cipher_type); |
414 | if (cipher == NULL) { | 442 | if (cipher == NULL) { |
415 | debug("Unsupported cipher %d used in key file %.200s.", | 443 | debug("Unsupported RSA1 cipher %d", cipher_type); |
416 | cipher_type, filename); | ||
417 | buffer_free(&buffer); | ||
418 | goto fail; | 444 | goto fail; |
419 | } | 445 | } |
420 | /* Initialize space for decrypted data. */ | 446 | /* Initialize space for decrypted data. */ |
421 | buffer_init(&decrypted); | 447 | buffer_init(&decrypted); |
422 | cp = buffer_append_space(&decrypted, buffer_len(&buffer)); | 448 | cp = buffer_append_space(&decrypted, buffer_len(blob)); |
423 | 449 | ||
424 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ | 450 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ |
425 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | 451 | cipher_set_key_string(&ciphercontext, cipher, passphrase, |
426 | CIPHER_DECRYPT); | 452 | CIPHER_DECRYPT); |
427 | cipher_crypt(&ciphercontext, cp, | 453 | cipher_crypt(&ciphercontext, cp, |
428 | buffer_ptr(&buffer), buffer_len(&buffer)); | 454 | buffer_ptr(blob), buffer_len(blob)); |
429 | cipher_cleanup(&ciphercontext); | 455 | cipher_cleanup(&ciphercontext); |
430 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | 456 | memset(&ciphercontext, 0, sizeof(ciphercontext)); |
431 | buffer_free(&buffer); | 457 | buffer_clear(blob); |
432 | 458 | ||
433 | check1 = buffer_get_char(&decrypted); | 459 | check1 = buffer_get_char(&decrypted); |
434 | check2 = buffer_get_char(&decrypted); | 460 | check2 = buffer_get_char(&decrypted); |
435 | if (check1 != buffer_get_char(&decrypted) || | 461 | if (check1 != buffer_get_char(&decrypted) || |
436 | check2 != buffer_get_char(&decrypted)) { | 462 | check2 != buffer_get_char(&decrypted)) { |
437 | if (strcmp(passphrase, "") != 0) | 463 | if (strcmp(passphrase, "") != 0) |
438 | debug("Bad passphrase supplied for key file %.200s.", | 464 | debug("Bad passphrase supplied for RSA1 key"); |
439 | filename); | ||
440 | /* Bad passphrase. */ | 465 | /* Bad passphrase. */ |
441 | buffer_free(&decrypted); | 466 | buffer_free(&decrypted); |
442 | goto fail; | 467 | goto fail; |
@@ -455,38 +480,37 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase, | |||
455 | 480 | ||
456 | /* enable blinding */ | 481 | /* enable blinding */ |
457 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | 482 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
458 | error("key_load_private_rsa1: RSA_blinding_on failed"); | 483 | error("%s: RSA_blinding_on failed", __func__); |
459 | goto fail; | 484 | goto fail; |
460 | } | 485 | } |
461 | close(fd); | ||
462 | return prv; | 486 | return prv; |
463 | 487 | ||
464 | fail: | 488 | fail: |
465 | if (commentp) | 489 | if (commentp) |
466 | xfree(*commentp); | 490 | xfree(*commentp); |
467 | close(fd); | ||
468 | key_free(prv); | 491 | key_free(prv); |
469 | return NULL; | 492 | return NULL; |
470 | } | 493 | } |
471 | 494 | ||
472 | Key * | 495 | static Key * |
473 | key_load_private_pem(int fd, int type, const char *passphrase, | 496 | key_parse_private_pem(Buffer *blob, int type, const char *passphrase, |
474 | char **commentp) | 497 | char **commentp) |
475 | { | 498 | { |
476 | FILE *fp; | ||
477 | EVP_PKEY *pk = NULL; | 499 | EVP_PKEY *pk = NULL; |
478 | Key *prv = NULL; | 500 | Key *prv = NULL; |
479 | char *name = "<no key>"; | 501 | char *name = "<no key>"; |
502 | BIO *bio; | ||
480 | 503 | ||
481 | fp = fdopen(fd, "r"); | 504 | if ((bio = BIO_new_mem_buf(buffer_ptr(blob), |
482 | if (fp == NULL) { | 505 | buffer_len(blob))) == NULL) { |
483 | error("fdopen failed: %s", strerror(errno)); | 506 | error("%s: BIO_new_mem_buf failed", __func__); |
484 | close(fd); | ||
485 | return NULL; | 507 | return NULL; |
486 | } | 508 | } |
487 | pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); | 509 | |
510 | pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); | ||
511 | BIO_free(bio); | ||
488 | if (pk == NULL) { | 512 | if (pk == NULL) { |
489 | debug("PEM_read_PrivateKey failed"); | 513 | debug("%s: PEM_read_PrivateKey failed", __func__); |
490 | (void)ERR_get_error(); | 514 | (void)ERR_get_error(); |
491 | } else if (pk->type == EVP_PKEY_RSA && | 515 | } else if (pk->type == EVP_PKEY_RSA && |
492 | (type == KEY_UNSPEC||type==KEY_RSA)) { | 516 | (type == KEY_UNSPEC||type==KEY_RSA)) { |
@@ -498,7 +522,7 @@ key_load_private_pem(int fd, int type, const char *passphrase, | |||
498 | RSA_print_fp(stderr, prv->rsa, 8); | 522 | RSA_print_fp(stderr, prv->rsa, 8); |
499 | #endif | 523 | #endif |
500 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | 524 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
501 | error("key_load_private_pem: RSA_blinding_on failed"); | 525 | error("%s: RSA_blinding_on failed", __func__); |
502 | key_free(prv); | 526 | key_free(prv); |
503 | prv = NULL; | 527 | prv = NULL; |
504 | } | 528 | } |
@@ -511,11 +535,31 @@ key_load_private_pem(int fd, int type, const char *passphrase, | |||
511 | #ifdef DEBUG_PK | 535 | #ifdef DEBUG_PK |
512 | DSA_print_fp(stderr, prv->dsa, 8); | 536 | DSA_print_fp(stderr, prv->dsa, 8); |
513 | #endif | 537 | #endif |
538 | #ifdef OPENSSL_HAS_ECC | ||
539 | } else if (pk->type == EVP_PKEY_EC && | ||
540 | (type == KEY_UNSPEC||type==KEY_ECDSA)) { | ||
541 | prv = key_new(KEY_UNSPEC); | ||
542 | prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); | ||
543 | prv->type = KEY_ECDSA; | ||
544 | if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || | ||
545 | key_curve_nid_to_name(prv->ecdsa_nid) == NULL || | ||
546 | key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), | ||
547 | EC_KEY_get0_public_key(prv->ecdsa)) != 0 || | ||
548 | key_ec_validate_private(prv->ecdsa) != 0) { | ||
549 | error("%s: bad ECDSA key", __func__); | ||
550 | key_free(prv); | ||
551 | prv = NULL; | ||
552 | } | ||
553 | name = "ecdsa w/o comment"; | ||
554 | #ifdef DEBUG_PK | ||
555 | if (prv != NULL && prv->ecdsa != NULL) | ||
556 | key_dump_ec_key(prv->ecdsa); | ||
557 | #endif | ||
558 | #endif /* OPENSSL_HAS_ECC */ | ||
514 | } else { | 559 | } else { |
515 | error("PEM_read_PrivateKey: mismatch or " | 560 | error("%s: PEM_read_PrivateKey: mismatch or " |
516 | "unknown EVP_PKEY save_type %d", pk->save_type); | 561 | "unknown EVP_PKEY save_type %d", __func__, pk->save_type); |
517 | } | 562 | } |
518 | fclose(fp); | ||
519 | if (pk != NULL) | 563 | if (pk != NULL) |
520 | EVP_PKEY_free(pk); | 564 | EVP_PKEY_free(pk); |
521 | if (prv != NULL && commentp) | 565 | if (prv != NULL && commentp) |
@@ -525,6 +569,23 @@ key_load_private_pem(int fd, int type, const char *passphrase, | |||
525 | return prv; | 569 | return prv; |
526 | } | 570 | } |
527 | 571 | ||
572 | Key * | ||
573 | key_load_private_pem(int fd, int type, const char *passphrase, | ||
574 | char **commentp) | ||
575 | { | ||
576 | Buffer buffer; | ||
577 | Key *prv; | ||
578 | |||
579 | buffer_init(&buffer); | ||
580 | if (!key_load_file(fd, NULL, &buffer)) { | ||
581 | buffer_free(&buffer); | ||
582 | return NULL; | ||
583 | } | ||
584 | prv = key_parse_private_pem(&buffer, type, passphrase, commentp); | ||
585 | buffer_free(&buffer); | ||
586 | return prv; | ||
587 | } | ||
588 | |||
528 | int | 589 | int |
529 | key_perm_ok(int fd, const char *filename) | 590 | key_perm_ok(int fd, const char *filename) |
530 | { | 591 | { |
@@ -553,11 +614,31 @@ key_perm_ok(int fd, const char *filename) | |||
553 | return 1; | 614 | return 1; |
554 | } | 615 | } |
555 | 616 | ||
617 | static Key * | ||
618 | key_parse_private_type(Buffer *blob, int type, const char *passphrase, | ||
619 | char **commentp) | ||
620 | { | ||
621 | switch (type) { | ||
622 | case KEY_RSA1: | ||
623 | return key_parse_private_rsa1(blob, passphrase, commentp); | ||
624 | case KEY_DSA: | ||
625 | case KEY_ECDSA: | ||
626 | case KEY_RSA: | ||
627 | case KEY_UNSPEC: | ||
628 | return key_parse_private_pem(blob, type, passphrase, commentp); | ||
629 | default: | ||
630 | break; | ||
631 | } | ||
632 | return NULL; | ||
633 | } | ||
634 | |||
556 | Key * | 635 | Key * |
557 | key_load_private_type(int type, const char *filename, const char *passphrase, | 636 | key_load_private_type(int type, const char *filename, const char *passphrase, |
558 | char **commentp, int *perm_ok) | 637 | char **commentp, int *perm_ok) |
559 | { | 638 | { |
560 | int fd; | 639 | int fd; |
640 | Key *ret; | ||
641 | Buffer buffer; | ||
561 | 642 | ||
562 | fd = open(filename, O_RDONLY); | 643 | fd = open(filename, O_RDONLY); |
563 | if (fd < 0) { | 644 | if (fd < 0) { |
@@ -576,21 +657,17 @@ key_load_private_type(int type, const char *filename, const char *passphrase, | |||
576 | } | 657 | } |
577 | if (perm_ok != NULL) | 658 | if (perm_ok != NULL) |
578 | *perm_ok = 1; | 659 | *perm_ok = 1; |
579 | switch (type) { | 660 | |
580 | case KEY_RSA1: | 661 | buffer_init(&buffer); |
581 | return key_load_private_rsa1(fd, filename, passphrase, | 662 | if (!key_load_file(fd, filename, &buffer)) { |
582 | commentp); | 663 | buffer_free(&buffer); |
583 | /* closes fd */ | ||
584 | case KEY_DSA: | ||
585 | case KEY_RSA: | ||
586 | case KEY_UNSPEC: | ||
587 | return key_load_private_pem(fd, type, passphrase, commentp); | ||
588 | /* closes fd */ | ||
589 | default: | ||
590 | close(fd); | 664 | close(fd); |
591 | break; | 665 | return NULL; |
592 | } | 666 | } |
593 | return NULL; | 667 | close(fd); |
668 | ret = key_parse_private_type(&buffer, type, passphrase, commentp); | ||
669 | buffer_free(&buffer); | ||
670 | return ret; | ||
594 | } | 671 | } |
595 | 672 | ||
596 | Key * | 673 | Key * |
@@ -598,6 +675,7 @@ key_load_private(const char *filename, const char *passphrase, | |||
598 | char **commentp) | 675 | char **commentp) |
599 | { | 676 | { |
600 | Key *pub, *prv; | 677 | Key *pub, *prv; |
678 | Buffer buffer, pubcopy; | ||
601 | int fd; | 679 | int fd; |
602 | 680 | ||
603 | fd = open(filename, O_RDONLY); | 681 | fd = open(filename, O_RDONLY); |
@@ -611,20 +689,33 @@ key_load_private(const char *filename, const char *passphrase, | |||
611 | close(fd); | 689 | close(fd); |
612 | return NULL; | 690 | return NULL; |
613 | } | 691 | } |
614 | pub = key_load_public_rsa1(fd, filename, commentp); | 692 | |
615 | lseek(fd, (off_t) 0, SEEK_SET); /* rewind */ | 693 | buffer_init(&buffer); |
694 | if (!key_load_file(fd, filename, &buffer)) { | ||
695 | buffer_free(&buffer); | ||
696 | close(fd); | ||
697 | return NULL; | ||
698 | } | ||
699 | close(fd); | ||
700 | |||
701 | buffer_init(&pubcopy); | ||
702 | buffer_append(&pubcopy, buffer_ptr(&buffer), buffer_len(&buffer)); | ||
703 | /* it's a SSH v1 key if the public key part is readable */ | ||
704 | pub = key_parse_public_rsa1(&pubcopy, commentp); | ||
705 | buffer_free(&pubcopy); | ||
616 | if (pub == NULL) { | 706 | if (pub == NULL) { |
617 | /* closes fd */ | 707 | prv = key_parse_private_type(&buffer, KEY_UNSPEC, |
618 | prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); | 708 | passphrase, NULL); |
619 | /* use the filename as a comment for PEM */ | 709 | /* use the filename as a comment for PEM */ |
620 | if (commentp && prv) | 710 | if (commentp && prv) |
621 | *commentp = xstrdup(filename); | 711 | *commentp = xstrdup(filename); |
622 | } else { | 712 | } else { |
623 | /* it's a SSH v1 key if the public key part is readable */ | ||
624 | key_free(pub); | 713 | key_free(pub); |
625 | /* closes fd */ | 714 | /* key_parse_public_rsa1() has already loaded the comment */ |
626 | prv = key_load_private_rsa1(fd, filename, passphrase, NULL); | 715 | prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase, |
716 | NULL); | ||
627 | } | 717 | } |
718 | buffer_free(&buffer); | ||
628 | return prv; | 719 | return prv; |
629 | } | 720 | } |
630 | 721 | ||
@@ -722,6 +813,7 @@ key_load_private_cert(int type, const char *filename, const char *passphrase, | |||
722 | switch (type) { | 813 | switch (type) { |
723 | case KEY_RSA: | 814 | case KEY_RSA: |
724 | case KEY_DSA: | 815 | case KEY_DSA: |
816 | case KEY_ECDSA: | ||
725 | break; | 817 | break; |
726 | default: | 818 | default: |
727 | error("%s: unsupported key type", __func__); | 819 | error("%s: unsupported key type", __func__); |