diff options
author | Colin Watson <cjwatson@debian.org> | 2011-01-24 11:46:57 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2011-01-24 11:46:57 +0000 |
commit | 0970072c89b079b022538e3c366fbfa2c53fc821 (patch) | |
tree | b7024712d74234bb5a8b036ccbc9109e2e211296 /authfile.c | |
parent | 4e8aa4da57000c7bba8e5c49163bc0c0ca383f78 (diff) | |
parent | 478ff799463ca926a8dfbabf058f4e84aaffc65a (diff) |
merge 5.7p1
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 2bd887845..f2aec267a 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 |
@@ -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,156 +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; |
194 | #ifdef OPENSSL_HAS_ECC | ||
195 | case KEY_ECDSA: | ||
196 | success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, | ||
197 | cipher, passphrase, len, NULL, NULL); | ||
198 | break; | ||
199 | #endif | ||
216 | case KEY_RSA: | 200 | case KEY_RSA: |
217 | success = PEM_write_RSAPrivateKey(fp, key->rsa, | 201 | success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, |
218 | cipher, passphrase, len, NULL, NULL); | 202 | cipher, passphrase, len, NULL, NULL); |
219 | break; | 203 | break; |
220 | } | 204 | } |
221 | 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); | ||
222 | return success; | 212 | return success; |
223 | } | 213 | } |
224 | 214 | ||
225 | int | 215 | /* Save a key blob to a file */ |
226 | 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, | ||
227 | const char *comment) | 240 | const char *comment) |
228 | { | 241 | { |
229 | switch (key->type) { | 242 | switch (key->type) { |
230 | case KEY_RSA1: | 243 | case KEY_RSA1: |
231 | return key_save_private_rsa1(key, filename, passphrase, | 244 | return key_private_rsa1_to_blob(key, blob, passphrase, comment); |
232 | comment); | ||
233 | case KEY_DSA: | 245 | case KEY_DSA: |
246 | case KEY_ECDSA: | ||
234 | case KEY_RSA: | 247 | case KEY_RSA: |
235 | return key_save_private_pem(key, filename, passphrase, | 248 | return key_private_pem_to_blob(key, blob, passphrase, comment); |
236 | comment); | ||
237 | default: | 249 | default: |
238 | break; | 250 | error("%s: cannot save key type %d", __func__, key->type); |
251 | return 0; | ||
239 | } | 252 | } |
240 | error("key_save_private: cannot save key type %d", key->type); | 253 | } |
241 | 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; | ||
242 | } | 271 | } |
243 | 272 | ||
244 | /* | 273 | /* |
245 | * 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. |
246 | * encountered (the file does not exist or is not readable), and the key | ||
247 | * otherwise. | ||
248 | */ | 275 | */ |
249 | |||
250 | static Key * | 276 | static Key * |
251 | key_load_public_rsa1(int fd, const char *filename, char **commentp) | 277 | key_parse_public_rsa1(Buffer *blob, char **commentp) |
252 | { | 278 | { |
253 | Buffer buffer; | ||
254 | Key *pub; | 279 | Key *pub; |
255 | struct stat st; | 280 | |
256 | char *cp; | 281 | /* Check that it is at least big enough to contain the ID string. */ |
257 | 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 | { | ||
258 | size_t len; | 319 | size_t len; |
320 | u_char *cp; | ||
321 | struct stat st; | ||
259 | 322 | ||
260 | if (fstat(fd, &st) < 0) { | 323 | if (fstat(fd, &st) < 0) { |
261 | error("fstat for key file %.200s failed: %.100s", | 324 | error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, |
262 | filename, strerror(errno)); | 325 | filename == NULL ? "" : filename, |
263 | return NULL; | 326 | filename == NULL ? "" : " ", |
327 | strerror(errno)); | ||
328 | close(fd); | ||
329 | return 0; | ||
264 | } | 330 | } |
265 | if (st.st_size > 1*1024*1024) { | 331 | if (st.st_size > 1*1024*1024) { |
266 | error("key file %.200s too large", filename); | 332 | error("%s: key file %.200s%stoo large", __func__, |
267 | return NULL; | 333 | filename == NULL ? "" : filename, |
334 | filename == NULL ? "" : " "); | ||
335 | close(fd); | ||
336 | return 0; | ||
268 | } | 337 | } |
269 | len = (size_t)st.st_size; /* truncated */ | 338 | len = (size_t)st.st_size; /* truncated */ |
270 | 339 | ||
271 | buffer_init(&buffer); | 340 | buffer_init(blob); |
272 | cp = buffer_append_space(&buffer, len); | 341 | cp = buffer_append_space(blob, len); |
273 | 342 | ||
274 | if (atomicio(read, fd, cp, len) != len) { | 343 | if (atomicio(read, fd, cp, len) != len) { |
275 | 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 ? "" : " ", | ||
276 | strerror(errno)); | 347 | strerror(errno)); |
277 | buffer_free(&buffer); | 348 | buffer_clear(blob); |
278 | return NULL; | 349 | close(fd); |
350 | return 0; | ||
279 | } | 351 | } |
352 | return 1; | ||
353 | } | ||
280 | 354 | ||
281 | /* Check that it is at least big enough to contain the ID string. */ | 355 | /* |
282 | if (len < sizeof(authfile_id_string)) { | 356 | * Loads the public part of the ssh v1 key file. Returns NULL if an error was |
283 | 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)) { | ||
284 | buffer_free(&buffer); | 368 | buffer_free(&buffer); |
285 | return NULL; | 369 | return NULL; |
286 | } | 370 | } |
287 | /* | ||
288 | * Make sure it begins with the id string. Consume the id string | ||
289 | * from the buffer. | ||
290 | */ | ||
291 | for (i = 0; i < sizeof(authfile_id_string); i++) | ||
292 | if (buffer_get_char(&buffer) != authfile_id_string[i]) { | ||
293 | debug3("Not a RSA1 key file %.200s.", filename); | ||
294 | buffer_free(&buffer); | ||
295 | return NULL; | ||
296 | } | ||
297 | /* Skip cipher type and reserved data. */ | ||
298 | (void) buffer_get_char(&buffer); /* cipher type */ | ||
299 | (void) buffer_get_int(&buffer); /* reserved */ | ||
300 | |||
301 | /* Read the public key from the buffer. */ | ||
302 | (void) buffer_get_int(&buffer); | ||
303 | pub = key_new(KEY_RSA1); | ||
304 | buffer_get_bignum(&buffer, pub->rsa->n); | ||
305 | buffer_get_bignum(&buffer, pub->rsa->e); | ||
306 | if (commentp) | ||
307 | *commentp = buffer_get_string(&buffer, NULL); | ||
308 | /* The encrypted private part is not parsed by this function. */ | ||
309 | 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); | ||
310 | buffer_free(&buffer); | 375 | buffer_free(&buffer); |
311 | return pub; | 376 | return pub; |
312 | } | 377 | } |
@@ -329,113 +394,73 @@ key_load_public_type(int type, const char *filename, char **commentp) | |||
329 | return NULL; | 394 | return NULL; |
330 | } | 395 | } |
331 | 396 | ||
332 | /* | ||
333 | * Loads the private key from the file. Returns 0 if an error is encountered | ||
334 | * (file does not exist or is not readable, or passphrase is bad). This | ||
335 | * initializes the private key. | ||
336 | * Assumes we are called under uid of the owner of the file. | ||
337 | */ | ||
338 | |||
339 | static Key * | 397 | static Key * |
340 | key_load_private_rsa1(int fd, const char *filename, const char *passphrase, | 398 | key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) |
341 | char **commentp) | ||
342 | { | 399 | { |
343 | u_int i; | ||
344 | int check1, check2, cipher_type; | 400 | int check1, check2, cipher_type; |
345 | size_t len; | 401 | Buffer decrypted; |
346 | Buffer buffer, decrypted; | ||
347 | u_char *cp; | 402 | u_char *cp; |
348 | CipherContext ciphercontext; | 403 | CipherContext ciphercontext; |
349 | Cipher *cipher; | 404 | Cipher *cipher; |
350 | Key *prv = NULL; | 405 | Key *prv = NULL; |
351 | struct stat st; | ||
352 | |||
353 | if (fstat(fd, &st) < 0) { | ||
354 | error("fstat for key file %.200s failed: %.100s", | ||
355 | filename, strerror(errno)); | ||
356 | close(fd); | ||
357 | return NULL; | ||
358 | } | ||
359 | if (st.st_size > 1*1024*1024) { | ||
360 | error("key file %.200s too large", filename); | ||
361 | close(fd); | ||
362 | return (NULL); | ||
363 | } | ||
364 | len = (size_t)st.st_size; /* truncated */ | ||
365 | |||
366 | buffer_init(&buffer); | ||
367 | cp = buffer_append_space(&buffer, len); | ||
368 | |||
369 | if (atomicio(read, fd, cp, len) != len) { | ||
370 | debug("Read from key file %.200s failed: %.100s", filename, | ||
371 | strerror(errno)); | ||
372 | buffer_free(&buffer); | ||
373 | close(fd); | ||
374 | return NULL; | ||
375 | } | ||
376 | 406 | ||
377 | /* 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. */ |
378 | if (len < sizeof(authfile_id_string)) { | 408 | if (buffer_len(blob) < sizeof(authfile_id_string)) { |
379 | debug3("Not a RSA1 key file %.200s.", filename); | 409 | debug3("Truncated RSA1 identifier"); |
380 | buffer_free(&buffer); | ||
381 | close(fd); | ||
382 | return NULL; | 410 | return NULL; |
383 | } | 411 | } |
412 | |||
384 | /* | 413 | /* |
385 | * 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 |
386 | * from the buffer. | 415 | * from the buffer. |
387 | */ | 416 | */ |
388 | for (i = 0; i < sizeof(authfile_id_string); i++) | 417 | if (memcmp(buffer_ptr(blob), authfile_id_string, |
389 | if (buffer_get_char(&buffer) != authfile_id_string[i]) { | 418 | sizeof(authfile_id_string)) != 0) { |
390 | debug3("Not a RSA1 key file %.200s.", filename); | 419 | debug3("Incorrect RSA1 identifier"); |
391 | buffer_free(&buffer); | 420 | return NULL; |
392 | close(fd); | 421 | } |
393 | return NULL; | 422 | buffer_consume(blob, sizeof(authfile_id_string)); |
394 | } | ||
395 | 423 | ||
396 | /* Read cipher type. */ | 424 | /* Read cipher type. */ |
397 | cipher_type = buffer_get_char(&buffer); | 425 | cipher_type = buffer_get_char(blob); |
398 | (void) buffer_get_int(&buffer); /* Reserved data. */ | 426 | (void) buffer_get_int(blob); /* Reserved data. */ |
399 | 427 | ||
400 | /* Read the public key from the buffer. */ | 428 | /* Read the public key from the buffer. */ |
401 | (void) buffer_get_int(&buffer); | 429 | (void) buffer_get_int(blob); |
402 | prv = key_new_private(KEY_RSA1); | 430 | prv = key_new_private(KEY_RSA1); |
403 | 431 | ||
404 | buffer_get_bignum(&buffer, prv->rsa->n); | 432 | buffer_get_bignum(blob, prv->rsa->n); |
405 | buffer_get_bignum(&buffer, prv->rsa->e); | 433 | buffer_get_bignum(blob, prv->rsa->e); |
406 | if (commentp) | 434 | if (commentp) |
407 | *commentp = buffer_get_string(&buffer, NULL); | 435 | *commentp = buffer_get_string(blob, NULL); |
408 | else | 436 | else |
409 | xfree(buffer_get_string(&buffer, NULL)); | 437 | (void)buffer_get_string_ptr(blob, NULL); |
410 | 438 | ||
411 | /* Check that it is a supported cipher. */ | 439 | /* Check that it is a supported cipher. */ |
412 | cipher = cipher_by_number(cipher_type); | 440 | cipher = cipher_by_number(cipher_type); |
413 | if (cipher == NULL) { | 441 | if (cipher == NULL) { |
414 | debug("Unsupported cipher %d used in key file %.200s.", | 442 | debug("Unsupported RSA1 cipher %d", cipher_type); |
415 | cipher_type, filename); | ||
416 | buffer_free(&buffer); | ||
417 | goto fail; | 443 | goto fail; |
418 | } | 444 | } |
419 | /* Initialize space for decrypted data. */ | 445 | /* Initialize space for decrypted data. */ |
420 | buffer_init(&decrypted); | 446 | buffer_init(&decrypted); |
421 | cp = buffer_append_space(&decrypted, buffer_len(&buffer)); | 447 | cp = buffer_append_space(&decrypted, buffer_len(blob)); |
422 | 448 | ||
423 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ | 449 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ |
424 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | 450 | cipher_set_key_string(&ciphercontext, cipher, passphrase, |
425 | CIPHER_DECRYPT); | 451 | CIPHER_DECRYPT); |
426 | cipher_crypt(&ciphercontext, cp, | 452 | cipher_crypt(&ciphercontext, cp, |
427 | buffer_ptr(&buffer), buffer_len(&buffer)); | 453 | buffer_ptr(blob), buffer_len(blob)); |
428 | cipher_cleanup(&ciphercontext); | 454 | cipher_cleanup(&ciphercontext); |
429 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | 455 | memset(&ciphercontext, 0, sizeof(ciphercontext)); |
430 | buffer_free(&buffer); | 456 | buffer_clear(blob); |
431 | 457 | ||
432 | check1 = buffer_get_char(&decrypted); | 458 | check1 = buffer_get_char(&decrypted); |
433 | check2 = buffer_get_char(&decrypted); | 459 | check2 = buffer_get_char(&decrypted); |
434 | if (check1 != buffer_get_char(&decrypted) || | 460 | if (check1 != buffer_get_char(&decrypted) || |
435 | check2 != buffer_get_char(&decrypted)) { | 461 | check2 != buffer_get_char(&decrypted)) { |
436 | if (strcmp(passphrase, "") != 0) | 462 | if (strcmp(passphrase, "") != 0) |
437 | debug("Bad passphrase supplied for key file %.200s.", | 463 | debug("Bad passphrase supplied for RSA1 key"); |
438 | filename); | ||
439 | /* Bad passphrase. */ | 464 | /* Bad passphrase. */ |
440 | buffer_free(&decrypted); | 465 | buffer_free(&decrypted); |
441 | goto fail; | 466 | goto fail; |
@@ -454,38 +479,37 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase, | |||
454 | 479 | ||
455 | /* enable blinding */ | 480 | /* enable blinding */ |
456 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | 481 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
457 | error("key_load_private_rsa1: RSA_blinding_on failed"); | 482 | error("%s: RSA_blinding_on failed", __func__); |
458 | goto fail; | 483 | goto fail; |
459 | } | 484 | } |
460 | close(fd); | ||
461 | return prv; | 485 | return prv; |
462 | 486 | ||
463 | fail: | 487 | fail: |
464 | if (commentp) | 488 | if (commentp) |
465 | xfree(*commentp); | 489 | xfree(*commentp); |
466 | close(fd); | ||
467 | key_free(prv); | 490 | key_free(prv); |
468 | return NULL; | 491 | return NULL; |
469 | } | 492 | } |
470 | 493 | ||
471 | Key * | 494 | static Key * |
472 | key_load_private_pem(int fd, int type, const char *passphrase, | 495 | key_parse_private_pem(Buffer *blob, int type, const char *passphrase, |
473 | char **commentp) | 496 | char **commentp) |
474 | { | 497 | { |
475 | FILE *fp; | ||
476 | EVP_PKEY *pk = NULL; | 498 | EVP_PKEY *pk = NULL; |
477 | Key *prv = NULL; | 499 | Key *prv = NULL; |
478 | char *name = "<no key>"; | 500 | char *name = "<no key>"; |
501 | BIO *bio; | ||
479 | 502 | ||
480 | fp = fdopen(fd, "r"); | 503 | if ((bio = BIO_new_mem_buf(buffer_ptr(blob), |
481 | if (fp == NULL) { | 504 | buffer_len(blob))) == NULL) { |
482 | error("fdopen failed: %s", strerror(errno)); | 505 | error("%s: BIO_new_mem_buf failed", __func__); |
483 | close(fd); | ||
484 | return NULL; | 506 | return NULL; |
485 | } | 507 | } |
486 | 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); | ||
487 | if (pk == NULL) { | 511 | if (pk == NULL) { |
488 | debug("PEM_read_PrivateKey failed"); | 512 | debug("%s: PEM_read_PrivateKey failed", __func__); |
489 | (void)ERR_get_error(); | 513 | (void)ERR_get_error(); |
490 | } else if (pk->type == EVP_PKEY_RSA && | 514 | } else if (pk->type == EVP_PKEY_RSA && |
491 | (type == KEY_UNSPEC||type==KEY_RSA)) { | 515 | (type == KEY_UNSPEC||type==KEY_RSA)) { |
@@ -497,7 +521,7 @@ key_load_private_pem(int fd, int type, const char *passphrase, | |||
497 | RSA_print_fp(stderr, prv->rsa, 8); | 521 | RSA_print_fp(stderr, prv->rsa, 8); |
498 | #endif | 522 | #endif |
499 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { | 523 | if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
500 | error("key_load_private_pem: RSA_blinding_on failed"); | 524 | error("%s: RSA_blinding_on failed", __func__); |
501 | key_free(prv); | 525 | key_free(prv); |
502 | prv = NULL; | 526 | prv = NULL; |
503 | } | 527 | } |
@@ -510,11 +534,31 @@ key_load_private_pem(int fd, int type, const char *passphrase, | |||
510 | #ifdef DEBUG_PK | 534 | #ifdef DEBUG_PK |
511 | DSA_print_fp(stderr, prv->dsa, 8); | 535 | DSA_print_fp(stderr, prv->dsa, 8); |
512 | #endif | 536 | #endif |
537 | #ifdef OPENSSL_HAS_ECC | ||
538 | } else if (pk->type == EVP_PKEY_EC && | ||
539 | (type == KEY_UNSPEC||type==KEY_ECDSA)) { | ||
540 | prv = key_new(KEY_UNSPEC); | ||
541 | prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); | ||
542 | prv->type = KEY_ECDSA; | ||
543 | if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || | ||
544 | key_curve_nid_to_name(prv->ecdsa_nid) == NULL || | ||
545 | key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), | ||
546 | EC_KEY_get0_public_key(prv->ecdsa)) != 0 || | ||
547 | key_ec_validate_private(prv->ecdsa) != 0) { | ||
548 | error("%s: bad ECDSA key", __func__); | ||
549 | key_free(prv); | ||
550 | prv = NULL; | ||
551 | } | ||
552 | name = "ecdsa w/o comment"; | ||
553 | #ifdef DEBUG_PK | ||
554 | if (prv != NULL && prv->ecdsa != NULL) | ||
555 | key_dump_ec_key(prv->ecdsa); | ||
556 | #endif | ||
557 | #endif /* OPENSSL_HAS_ECC */ | ||
513 | } else { | 558 | } else { |
514 | error("PEM_read_PrivateKey: mismatch or " | 559 | error("%s: PEM_read_PrivateKey: mismatch or " |
515 | "unknown EVP_PKEY save_type %d", pk->save_type); | 560 | "unknown EVP_PKEY save_type %d", __func__, pk->save_type); |
516 | } | 561 | } |
517 | fclose(fp); | ||
518 | if (pk != NULL) | 562 | if (pk != NULL) |
519 | EVP_PKEY_free(pk); | 563 | EVP_PKEY_free(pk); |
520 | if (prv != NULL && commentp) | 564 | if (prv != NULL && commentp) |
@@ -524,6 +568,23 @@ key_load_private_pem(int fd, int type, const char *passphrase, | |||
524 | return prv; | 568 | return prv; |
525 | } | 569 | } |
526 | 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 | |||
527 | int | 588 | int |
528 | key_perm_ok(int fd, const char *filename) | 589 | key_perm_ok(int fd, const char *filename) |
529 | { | 590 | { |
@@ -552,11 +613,31 @@ key_perm_ok(int fd, const char *filename) | |||
552 | return 1; | 613 | return 1; |
553 | } | 614 | } |
554 | 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 | |||
555 | Key * | 634 | Key * |
556 | 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, |
557 | char **commentp, int *perm_ok) | 636 | char **commentp, int *perm_ok) |
558 | { | 637 | { |
559 | int fd; | 638 | int fd; |
639 | Key *ret; | ||
640 | Buffer buffer; | ||
560 | 641 | ||
561 | fd = open(filename, O_RDONLY); | 642 | fd = open(filename, O_RDONLY); |
562 | if (fd < 0) { | 643 | if (fd < 0) { |
@@ -575,21 +656,17 @@ key_load_private_type(int type, const char *filename, const char *passphrase, | |||
575 | } | 656 | } |
576 | if (perm_ok != NULL) | 657 | if (perm_ok != NULL) |
577 | *perm_ok = 1; | 658 | *perm_ok = 1; |
578 | switch (type) { | 659 | |
579 | case KEY_RSA1: | 660 | buffer_init(&buffer); |
580 | return key_load_private_rsa1(fd, filename, passphrase, | 661 | if (!key_load_file(fd, filename, &buffer)) { |
581 | commentp); | 662 | buffer_free(&buffer); |
582 | /* closes fd */ | ||
583 | case KEY_DSA: | ||
584 | case KEY_RSA: | ||
585 | case KEY_UNSPEC: | ||
586 | return key_load_private_pem(fd, type, passphrase, commentp); | ||
587 | /* closes fd */ | ||
588 | default: | ||
589 | close(fd); | 663 | close(fd); |
590 | break; | 664 | return NULL; |
591 | } | 665 | } |
592 | return NULL; | 666 | close(fd); |
667 | ret = key_parse_private_type(&buffer, type, passphrase, commentp); | ||
668 | buffer_free(&buffer); | ||
669 | return ret; | ||
593 | } | 670 | } |
594 | 671 | ||
595 | Key * | 672 | Key * |
@@ -597,6 +674,7 @@ key_load_private(const char *filename, const char *passphrase, | |||
597 | char **commentp) | 674 | char **commentp) |
598 | { | 675 | { |
599 | Key *pub, *prv; | 676 | Key *pub, *prv; |
677 | Buffer buffer, pubcopy; | ||
600 | int fd; | 678 | int fd; |
601 | 679 | ||
602 | fd = open(filename, O_RDONLY); | 680 | fd = open(filename, O_RDONLY); |
@@ -610,20 +688,33 @@ key_load_private(const char *filename, const char *passphrase, | |||
610 | close(fd); | 688 | close(fd); |
611 | return NULL; | 689 | return NULL; |
612 | } | 690 | } |
613 | pub = key_load_public_rsa1(fd, filename, commentp); | 691 | |
614 | 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); | ||
615 | if (pub == NULL) { | 705 | if (pub == NULL) { |
616 | /* closes fd */ | 706 | prv = key_parse_private_type(&buffer, KEY_UNSPEC, |
617 | prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); | 707 | passphrase, NULL); |
618 | /* use the filename as a comment for PEM */ | 708 | /* use the filename as a comment for PEM */ |
619 | if (commentp && prv) | 709 | if (commentp && prv) |
620 | *commentp = xstrdup(filename); | 710 | *commentp = xstrdup(filename); |
621 | } else { | 711 | } else { |
622 | /* it's a SSH v1 key if the public key part is readable */ | ||
623 | key_free(pub); | 712 | key_free(pub); |
624 | /* closes fd */ | 713 | /* key_parse_public_rsa1() has already loaded the comment */ |
625 | prv = key_load_private_rsa1(fd, filename, passphrase, NULL); | 714 | prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase, |
715 | NULL); | ||
626 | } | 716 | } |
717 | buffer_free(&buffer); | ||
627 | return prv; | 718 | return prv; |
628 | } | 719 | } |
629 | 720 | ||
@@ -721,6 +812,7 @@ key_load_private_cert(int type, const char *filename, const char *passphrase, | |||
721 | switch (type) { | 812 | switch (type) { |
722 | case KEY_RSA: | 813 | case KEY_RSA: |
723 | case KEY_DSA: | 814 | case KEY_DSA: |
815 | case KEY_ECDSA: | ||
724 | break; | 816 | break; |
725 | default: | 817 | default: |
726 | error("%s: unsupported key type", __func__); | 818 | error("%s: unsupported key type", __func__); |