authfile.c 13.8 KB
Newer Older
1
/* $OpenBSD: authfile.c,v 1.111 2015/02/23 16:55:51 djm Exp $ */
2
/*
3
 * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "includes.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
35
#include <stdarg.h>
36 37 38
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
39
#include <limits.h>
40 41 42 43 44 45 46 47 48

#include "cipher.h"
#include "key.h"
#include "ssh.h"
#include "log.h"
#include "authfile.h"
#include "rsa.h"
#include "misc.h"
#include "atomicio.h"
49 50 51
#include "sshbuf.h"
#include "ssherr.h"
#include "krl.h"
52 53 54 55 56

#define MAX_KEY_FILE_SIZE	(1024 * 1024)

/* Save a key blob to a file */
static int
57
sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
58
{
59
	int fd, oerrno;
60

61 62 63 64 65
	if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
		return SSH_ERR_SYSTEM_ERROR;
	if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
	    sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
		oerrno = errno;
66 67
		close(fd);
		unlink(filename);
68 69
		errno = oerrno;
		return SSH_ERR_SYSTEM_ERROR;
70 71
	}
	close(fd);
72
	return 0;
73 74 75
}

int
76 77 78
sshkey_save_private(struct sshkey *key, const char *filename,
    const char *passphrase, const char *comment,
    int force_new_format, const char *new_format_cipher, int new_format_rounds)
79
{
80 81
	struct sshbuf *keyblob = NULL;
	int r;
82

83 84 85 86
	if ((keyblob = sshbuf_new()) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
	    force_new_format, new_format_cipher, new_format_rounds)) != 0)
87
		goto out;
88
	if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
89
		goto out;
90
	r = 0;
91
 out:
92 93
	sshbuf_free(keyblob);
	return r;
94 95 96 97
}

/* Load a key from a fd into a buffer */
int
98
sshkey_load_file(int fd, struct sshbuf *blob)
99 100 101 102
{
	u_char buf[1024];
	size_t len;
	struct stat st;
103
	int r;
104

105 106
	if (fstat(fd, &st) < 0)
		return SSH_ERR_SYSTEM_ERROR;
107
	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
108 109
	    st.st_size > MAX_KEY_FILE_SIZE)
		return SSH_ERR_INVALID_FORMAT;
110 111 112 113
	for (;;) {
		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
			if (errno == EPIPE)
				break;
114 115
			r = SSH_ERR_SYSTEM_ERROR;
			goto out;
116
		}
117 118 119 120 121
		if ((r = sshbuf_put(blob, buf, len)) != 0)
			goto out;
		if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
			r = SSH_ERR_INVALID_FORMAT;
			goto out;
122 123 124
		}
	}
	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
125 126 127
	    st.st_size != (off_t)sshbuf_len(blob)) {
		r = SSH_ERR_FILE_CHANGED;
		goto out;
128
	}
129
	r = 0;
130

131 132 133 134 135
 out:
	explicit_bzero(buf, sizeof(buf));
	if (r != 0)
		sshbuf_reset(blob);
	return r;
136 137
}

138
#ifdef WITH_SSH1
139 140 141 142 143
/*
 * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
 * encountered (the file does not exist or is not readable), and the key
 * otherwise.
 */
144 145
static int
sshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
146
{
147 148
	struct sshbuf *b = NULL;
	int r;
149

150 151 152
	*keyp = NULL;
	if (commentp != NULL)
		*commentp = NULL;
153

154 155 156 157 158 159 160 161 162 163
	if ((b = sshbuf_new()) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	if ((r = sshkey_load_file(fd, b)) != 0)
		goto out;
	if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
		goto out;
	r = 0;
 out:
	sshbuf_free(b);
	return r;
164
}
165
#endif /* WITH_SSH1 */
166

167
/* XXX remove error() calls from here? */
168
int
169
sshkey_perm_ok(int fd, const char *filename)
170 171 172 173
{
	struct stat st;

	if (fstat(fd, &st) < 0)
174
		return SSH_ERR_SYSTEM_ERROR;
175 176 177 178 179 180 181 182 183 184 185 186 187 188
	/*
	 * if a key owned by the user is accessed, then we check the
	 * permissions of the file. if the key owned by a different user,
	 * then we don't care.
	 */
#ifdef HAVE_CYGWIN
	if (check_ntsec(filename))
#endif
	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
		error("Permissions 0%3.3o for '%s' are too open.",
		    (u_int)st.st_mode & 0777, filename);
189
		error("It is recommended that your private key files are NOT accessible by others.");
190
		error("This private key will be ignored.");
191
		return SSH_ERR_KEY_BAD_PERMISSIONS;
192
	}
193
	return 0;
194 195
}

196 197 198 199
/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
int
sshkey_load_private_type(int type, const char *filename, const char *passphrase,
    struct sshkey **keyp, char **commentp, int *perm_ok)
200
{
201
	int fd, r;
202

203 204 205 206 207
	*keyp = NULL;
	if (commentp != NULL)
		*commentp = NULL;

	if ((fd = open(filename, O_RDONLY)) < 0) {
208 209
		if (perm_ok != NULL)
			*perm_ok = 0;
210
		return SSH_ERR_SYSTEM_ERROR;
211
	}
212
	if (sshkey_perm_ok(fd, filename) != 0) {
213 214
		if (perm_ok != NULL)
			*perm_ok = 0;
215 216
		r = SSH_ERR_KEY_BAD_PERMISSIONS;
		goto out;
217 218 219 220
	}
	if (perm_ok != NULL)
		*perm_ok = 1;

221 222
	r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
 out:
223
	close(fd);
224
	return r;
225 226
}

227 228 229
int
sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
    struct sshkey **keyp, char **commentp)
230
{
231 232 233 234 235 236
	struct sshbuf *buffer = NULL;
	int r;

	if ((buffer = sshbuf_new()) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
237
	}
238 239 240 241 242 243 244 245 246 247 248
	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
	    (r = sshkey_parse_private_fileblob_type(buffer, type,
	    passphrase, keyp, commentp)) != 0)
		goto out;

	/* success */
	r = 0;
 out:
	if (buffer != NULL)
		sshbuf_free(buffer);
	return r;
249 250
}

251 252 253 254
/* XXX this is almost identical to sshkey_load_private_type() */
int
sshkey_load_private(const char *filename, const char *passphrase,
    struct sshkey **keyp, char **commentp)
255
{
256 257 258 259 260 261 262 263 264 265 266 267
	struct sshbuf *buffer = NULL;
	int r, fd;

	*keyp = NULL;
	if (commentp != NULL)
		*commentp = NULL;

	if ((fd = open(filename, O_RDONLY)) < 0)
		return SSH_ERR_SYSTEM_ERROR;
	if (sshkey_perm_ok(fd, filename) != 0) {
		r = SSH_ERR_KEY_BAD_PERMISSIONS;
		goto out;
268 269
	}

270 271 272
	if ((buffer = sshbuf_new()) == NULL) {
		r = SSH_ERR_ALLOC_FAIL;
		goto out;
273
	}
274 275 276 277 278 279
	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
	    (r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
	    keyp, commentp)) != 0)
		goto out;
	r = 0;
 out:
280
	close(fd);
281 282 283
	if (buffer != NULL)
		sshbuf_free(buffer);
	return r;
284 285 286
}

static int
287
sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
288 289 290 291 292
{
	FILE *f;
	char line[SSH_MAX_PUBKEY_BYTES];
	char *cp;
	u_long linenum = 0;
293
	int r;
294

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
	if (commentp != NULL)
		*commentp = NULL;
	if ((f = fopen(filename, "r")) == NULL)
		return SSH_ERR_SYSTEM_ERROR;
	while (read_keyfile_line(f, filename, line, sizeof(line),
		    &linenum) != -1) {
		cp = line;
		switch (*cp) {
		case '#':
		case '\n':
		case '\0':
			continue;
		}
		/* Abort loading if this looks like a private key */
		if (strncmp(cp, "-----BEGIN", 10) == 0 ||
		    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
			break;
		/* Skip leading whitespace. */
		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
			;
		if (*cp) {
			if ((r = sshkey_read(k, &cp)) == 0) {
				cp[strcspn(cp, "\r\n")] = '\0';
				if (commentp) {
					*commentp = strdup(*cp ?
					    cp : filename);
					if (*commentp == NULL)
						r = SSH_ERR_ALLOC_FAIL;
323
				}
324 325
				fclose(f);
				return r;
326 327 328
			}
		}
	}
329 330
	fclose(f);
	return SSH_ERR_INVALID_FORMAT;
331 332 333
}

/* load public key from ssh v1 private or any pubkey file */
334 335
int
sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
336
{
337 338 339 340 341 342 343 344
	struct sshkey *pub = NULL;
	char file[PATH_MAX];
	int r, fd;

	if (keyp != NULL)
		*keyp = NULL;
	if (commentp != NULL)
		*commentp = NULL;
345

346 347 348 349 350
	/* XXX should load file once and attempt to parse each format */

	if ((fd = open(filename, O_RDONLY)) < 0)
		goto skip;
#ifdef WITH_SSH1
351
	/* try rsa1 private key */
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
	r = sshkey_load_public_rsa1(fd, keyp, commentp);
	close(fd);
	switch (r) {
	case SSH_ERR_INTERNAL_ERROR:
	case SSH_ERR_ALLOC_FAIL:
	case SSH_ERR_INVALID_ARGUMENT:
	case SSH_ERR_SYSTEM_ERROR:
	case 0:
		return r;
	}
#endif /* WITH_SSH1 */

	/* try ssh2 public key */
	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
		if (keyp != NULL)
			*keyp = pub;
		return 0;
	}
	sshkey_free(pub);
373

374
#ifdef WITH_SSH1
375
	/* try rsa1 public key */
376 377 378 379 380 381 382 383 384
	if ((pub = sshkey_new(KEY_RSA1)) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
		if (keyp != NULL)
			*keyp = pub;
		return 0;
	}
	sshkey_free(pub);
#endif /* WITH_SSH1 */
385

386 387 388 389 390
 skip:
	/* try .pub suffix */
	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
		return SSH_ERR_ALLOC_FAIL;
	r = SSH_ERR_ALLOC_FAIL;	/* in case strlcpy or strlcat fail */
391 392
	if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
	    (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
393 394 395 396 397 398 399 400
	    (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
		if (keyp != NULL)
			*keyp = pub;
		return 0;
	}
	sshkey_free(pub);

	return r;
401 402 403
}

/* Load the certificate associated with the named private key */
404 405
int
sshkey_load_cert(const char *filename, struct sshkey **keyp)
406
{
407 408 409 410 411 412 413 414 415 416 417
	struct sshkey *pub = NULL;
	char *file = NULL;
	int r = SSH_ERR_INTERNAL_ERROR;

	*keyp = NULL;

	if (asprintf(&file, "%s-cert.pub", filename) == -1)
		return SSH_ERR_ALLOC_FAIL;

	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
		goto out;
418
	}
419 420 421 422 423 424 425 426 427 428 429 430 431
	if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
		goto out;

	*keyp = pub;
	pub = NULL;
	r = 0;

 out:
	if (file != NULL)
		free(file);
	if (pub != NULL)
		sshkey_free(pub);
	return r;
432 433 434
}

/* Load private key and certificate */
435 436 437
int
sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
    struct sshkey **keyp, int *perm_ok)
438
{
439 440 441 442
	struct sshkey *key = NULL, *cert = NULL;
	int r;

	*keyp = NULL;
443 444

	switch (type) {
445
#ifdef WITH_OPENSSL
446 447 448
	case KEY_RSA:
	case KEY_DSA:
	case KEY_ECDSA:
449 450 451
	case KEY_ED25519:
#endif /* WITH_OPENSSL */
	case KEY_UNSPEC:
452 453
		break;
	default:
454
		return SSH_ERR_KEY_TYPE_UNKNOWN;
455 456
	}

457 458 459 460
	if ((r = sshkey_load_private_type(type, filename,
	    passphrase, &key, NULL, perm_ok)) != 0 ||
	    (r = sshkey_load_cert(filename, &cert)) != 0)
		goto out;
461 462

	/* Make sure the private key matches the certificate */
463 464 465
	if (sshkey_equal_public(key, cert) == 0) {
		r = SSH_ERR_KEY_CERT_MISMATCH;
		goto out;
466 467
	}

468 469 470 471 472 473 474 475 476 477 478 479
	if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 ||
	    (r = sshkey_cert_copy(cert, key)) != 0)
		goto out;
	r = 0;
	*keyp = key;
	key = NULL;
 out:
	if (key != NULL)
		sshkey_free(key);
	if (cert != NULL)
		sshkey_free(cert);
	return r;
480 481 482
}

/*
483 484 485
 * Returns success if the specified "key" is listed in the file "filename",
 * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
 * If "strict_type" is set then the key type must match exactly,
486
 * otherwise a comparison that ignores certficiate data is performed.
487 488
 * If "check_ca" is set and "key" is a certificate, then its CA key is
 * also checked and sshkey_in_file() will return success if either is found.
489 490
 */
int
491 492
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
    int check_ca)
493 494 495 496 497
{
	FILE *f;
	char line[SSH_MAX_PUBKEY_BYTES];
	char *cp;
	u_long linenum = 0;
498 499 500 501 502 503 504
	int r = 0;
	struct sshkey *pub = NULL;
	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
	    strict_type ?  sshkey_equal : sshkey_equal_public;

	if ((f = fopen(filename, "r")) == NULL)
		return SSH_ERR_SYSTEM_ERROR;
505 506

	while (read_keyfile_line(f, filename, line, sizeof(line),
507
	    &linenum) != -1) {
508 509 510 511 512 513 514 515 516 517 518 519 520 521
		cp = line;

		/* Skip leading whitespace. */
		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
			;

		/* Skip comments and empty lines */
		switch (*cp) {
		case '#':
		case '\n':
		case '\0':
			continue;
		}

522 523 524
		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
			r = SSH_ERR_ALLOC_FAIL;
			goto out;
525
		}
526 527 528 529 530 531 532
		if ((r = sshkey_read(pub, &cp)) != 0)
			goto out;
		if (sshkey_compare(key, pub) ||
		    (check_ca && sshkey_is_cert(key) &&
		    sshkey_compare(key->cert->signature_key, pub))) {
			r = 0;
			goto out;
533
		}
534 535
		sshkey_free(pub);
		pub = NULL;
536
	}
537 538 539 540
	r = SSH_ERR_KEY_NOT_FOUND;
 out:
	if (pub != NULL)
		sshkey_free(pub);
541
	fclose(f);
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
	return r;
}

/*
 * Checks whether the specified key is revoked, returning 0 if not,
 * SSH_ERR_KEY_REVOKED if it is or another error code if something
 * unexpected happened.
 * This will check both the key and, if it is a certificate, its CA key too.
 * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
 */
int
sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
{
	int r;

	r = ssh_krl_file_contains_key(revoked_keys_file, key);
	/* If this was not a KRL to begin with then continue below */
	if (r != SSH_ERR_KRL_BAD_MAGIC)
		return r;

	/*
	 * If the file is not a KRL or we can't handle KRLs then attempt to
	 * parse the file as a flat list of keys.
	 */
	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
	case 0:
		/* Key found => revoked */
		return SSH_ERR_KEY_REVOKED;
	case SSH_ERR_KEY_NOT_FOUND:
		/* Key not found => not revoked */
		return 0;
	default:
		/* Some other error occurred */
		return r;
	}
577 578
}