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