diff options
author | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
commit | 626f1d986ff72aa514da63e34744e1de9cf21b9a (patch) | |
tree | d215a5280bc2e57251e4a9e08bfd3674ad824a94 /authfile.c | |
parent | 6ed622cb6fe8f71bbe0d998cdd12280410bfb420 (diff) | |
parent | 0970072c89b079b022538e3c366fbfa2c53fc821 (diff) |
* New upstream release (http://www.openssh.org/txt/release-5.7):
- Implement Elliptic Curve Cryptography modes for key exchange (ECDH)
and host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA
offer better performance than plain DH and DSA at the same equivalent
symmetric key length, as well as much shorter keys.
- sftp(1)/sftp-server(8): add a protocol extension to support a hard
link operation. It is available through the "ln" command in the
client. The old "ln" behaviour of creating a symlink is available
using its "-s" option or through the preexisting "symlink" command.
- scp(1): Add a new -3 option to scp: Copies between two remote hosts
are transferred through the local host (closes: #508613).
- ssh(1): "atomically" create the listening mux socket by binding it on
a temporary name and then linking it into position after listen() has
succeeded. This allows the mux clients to determine that the server
socket is either ready or stale without races (closes: #454784).
Stale server sockets are now automatically removed (closes: #523250).
- ssh(1): install a SIGCHLD handler to reap expired child process
(closes: #594687).
- ssh(1)/ssh-agent(1): honour $TMPDIR for client xauth and ssh-agent
temporary directories (closes: #357469, although only if you arrange
for ssh-agent to actually see $TMPDIR since the setgid bit will cause
it to be stripped off).
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__); |