GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../authfile.c Lines: 0 205 0.0 %
Date: 2017-11-13 Branches: 0 173 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: authfile.c,v 1.127 2017/07/01 13:50:45 djm Exp $ */
2
/*
3
 * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
27
#include <sys/types.h>
28
#include <sys/stat.h>
29
#include <sys/uio.h>
30
31
#include <errno.h>
32
#include <fcntl.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <unistd.h>
37
#include <limits.h>
38
39
#include "cipher.h"
40
#include "ssh.h"
41
#include "log.h"
42
#include "authfile.h"
43
#include "misc.h"
44
#include "atomicio.h"
45
#include "sshkey.h"
46
#include "sshbuf.h"
47
#include "ssherr.h"
48
#include "krl.h"
49
50
#define MAX_KEY_FILE_SIZE	(1024 * 1024)
51
52
/* Save a key blob to a file */
53
static int
54
sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
55
{
56
	int fd, oerrno;
57
58
	if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
59
		return SSH_ERR_SYSTEM_ERROR;
60
	if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
61
	    sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
62
		oerrno = errno;
63
		close(fd);
64
		unlink(filename);
65
		errno = oerrno;
66
		return SSH_ERR_SYSTEM_ERROR;
67
	}
68
	close(fd);
69
	return 0;
70
}
71
72
int
73
sshkey_save_private(struct sshkey *key, const char *filename,
74
    const char *passphrase, const char *comment,
75
    int force_new_format, const char *new_format_cipher, int new_format_rounds)
76
{
77
	struct sshbuf *keyblob = NULL;
78
	int r;
79
80
	if ((keyblob = sshbuf_new()) == NULL)
81
		return SSH_ERR_ALLOC_FAIL;
82
	if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
83
	    force_new_format, new_format_cipher, new_format_rounds)) != 0)
84
		goto out;
85
	if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
86
		goto out;
87
	r = 0;
88
 out:
89
	sshbuf_free(keyblob);
90
	return r;
91
}
92
93
/* Load a key from a fd into a buffer */
94
int
95
sshkey_load_file(int fd, struct sshbuf *blob)
96
{
97
	u_char buf[1024];
98
	size_t len;
99
	struct stat st;
100
	int r;
101
102
	if (fstat(fd, &st) < 0)
103
		return SSH_ERR_SYSTEM_ERROR;
104
	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
105
	    st.st_size > MAX_KEY_FILE_SIZE)
106
		return SSH_ERR_INVALID_FORMAT;
107
	for (;;) {
108
		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
109
			if (errno == EPIPE)
110
				break;
111
			r = SSH_ERR_SYSTEM_ERROR;
112
			goto out;
113
		}
114
		if ((r = sshbuf_put(blob, buf, len)) != 0)
115
			goto out;
116
		if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
117
			r = SSH_ERR_INVALID_FORMAT;
118
			goto out;
119
		}
120
	}
121
	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
122
	    st.st_size != (off_t)sshbuf_len(blob)) {
123
		r = SSH_ERR_FILE_CHANGED;
124
		goto out;
125
	}
126
	r = 0;
127
128
 out:
129
	explicit_bzero(buf, sizeof(buf));
130
	if (r != 0)
131
		sshbuf_reset(blob);
132
	return r;
133
}
134
135
136
/* XXX remove error() calls from here? */
137
int
138
sshkey_perm_ok(int fd, const char *filename)
139
{
140
	struct stat st;
141
142
	if (fstat(fd, &st) < 0)
143
		return SSH_ERR_SYSTEM_ERROR;
144
	/*
145
	 * if a key owned by the user is accessed, then we check the
146
	 * permissions of the file. if the key owned by a different user,
147
	 * then we don't care.
148
	 */
149
	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
150
		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
151
		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
152
		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
153
		error("Permissions 0%3.3o for '%s' are too open.",
154
		    (u_int)st.st_mode & 0777, filename);
155
		error("It is required that your private key files are NOT accessible by others.");
156
		error("This private key will be ignored.");
157
		return SSH_ERR_KEY_BAD_PERMISSIONS;
158
	}
159
	return 0;
160
}
161
162
/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
163
int
164
sshkey_load_private_type(int type, const char *filename, const char *passphrase,
165
    struct sshkey **keyp, char **commentp, int *perm_ok)
166
{
167
	int fd, r;
168
169
	if (keyp != NULL)
170
		*keyp = NULL;
171
	if (commentp != NULL)
172
		*commentp = NULL;
173
174
	if ((fd = open(filename, O_RDONLY)) < 0) {
175
		if (perm_ok != NULL)
176
			*perm_ok = 0;
177
		return SSH_ERR_SYSTEM_ERROR;
178
	}
179
	if (sshkey_perm_ok(fd, filename) != 0) {
180
		if (perm_ok != NULL)
181
			*perm_ok = 0;
182
		r = SSH_ERR_KEY_BAD_PERMISSIONS;
183
		goto out;
184
	}
185
	if (perm_ok != NULL)
186
		*perm_ok = 1;
187
188
	r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
189
 out:
190
	close(fd);
191
	return r;
192
}
193
194
int
195
sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
196
    struct sshkey **keyp, char **commentp)
197
{
198
	struct sshbuf *buffer = NULL;
199
	int r;
200
201
	if (keyp != NULL)
202
		*keyp = NULL;
203
	if ((buffer = sshbuf_new()) == NULL) {
204
		r = SSH_ERR_ALLOC_FAIL;
205
		goto out;
206
	}
207
	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
208
	    (r = sshkey_parse_private_fileblob_type(buffer, type,
209
	    passphrase, keyp, commentp)) != 0)
210
		goto out;
211
212
	/* success */
213
	r = 0;
214
 out:
215
	sshbuf_free(buffer);
216
	return r;
217
}
218
219
/* XXX this is almost identical to sshkey_load_private_type() */
220
int
221
sshkey_load_private(const char *filename, const char *passphrase,
222
    struct sshkey **keyp, char **commentp)
223
{
224
	struct sshbuf *buffer = NULL;
225
	int r, fd;
226
227
	if (keyp != NULL)
228
		*keyp = NULL;
229
	if (commentp != NULL)
230
		*commentp = NULL;
231
232
	if ((fd = open(filename, O_RDONLY)) < 0)
233
		return SSH_ERR_SYSTEM_ERROR;
234
	if (sshkey_perm_ok(fd, filename) != 0) {
235
		r = SSH_ERR_KEY_BAD_PERMISSIONS;
236
		goto out;
237
	}
238
239
	if ((buffer = sshbuf_new()) == NULL) {
240
		r = SSH_ERR_ALLOC_FAIL;
241
		goto out;
242
	}
243
	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
244
	    (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
245
	    commentp)) != 0)
246
		goto out;
247
	r = 0;
248
 out:
249
	close(fd);
250
	sshbuf_free(buffer);
251
	return r;
252
}
253
254
static int
255
sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
256
{
257
	FILE *f;
258
	char line[SSH_MAX_PUBKEY_BYTES];
259
	char *cp;
260
	u_long linenum = 0;
261
	int r;
262
263
	if (commentp != NULL)
264
		*commentp = NULL;
265
	if ((f = fopen(filename, "r")) == NULL)
266
		return SSH_ERR_SYSTEM_ERROR;
267
	while (read_keyfile_line(f, filename, line, sizeof(line),
268
		    &linenum) != -1) {
269
		cp = line;
270
		switch (*cp) {
271
		case '#':
272
		case '\n':
273
		case '\0':
274
			continue;
275
		}
276
		/* Abort loading if this looks like a private key */
277
		if (strncmp(cp, "-----BEGIN", 10) == 0 ||
278
		    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
279
			break;
280
		/* Skip leading whitespace. */
281
		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
282
			;
283
		if (*cp) {
284
			if ((r = sshkey_read(k, &cp)) == 0) {
285
				cp[strcspn(cp, "\r\n")] = '\0';
286
				if (commentp) {
287
					*commentp = strdup(*cp ?
288
					    cp : filename);
289
					if (*commentp == NULL)
290
						r = SSH_ERR_ALLOC_FAIL;
291
				}
292
				fclose(f);
293
				return r;
294
			}
295
		}
296
	}
297
	fclose(f);
298
	return SSH_ERR_INVALID_FORMAT;
299
}
300
301
/* load public key from any pubkey file */
302
int
303
sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
304
{
305
	struct sshkey *pub = NULL;
306
	char *file = NULL;
307
	int r;
308
309
	if (keyp != NULL)
310
		*keyp = NULL;
311
	if (commentp != NULL)
312
		*commentp = NULL;
313
314
	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
315
		return SSH_ERR_ALLOC_FAIL;
316
	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
317
		if (keyp != NULL) {
318
			*keyp = pub;
319
			pub = NULL;
320
		}
321
		r = 0;
322
		goto out;
323
	}
324
	sshkey_free(pub);
325
326
	/* try .pub suffix */
327
	if (asprintf(&file, "%s.pub", filename) == -1)
328
		return SSH_ERR_ALLOC_FAIL;
329
	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
330
		r = SSH_ERR_ALLOC_FAIL;
331
		goto out;
332
	}
333
	if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) {
334
		if (keyp != NULL) {
335
			*keyp = pub;
336
			pub = NULL;
337
		}
338
		r = 0;
339
	}
340
 out:
341
	free(file);
342
	sshkey_free(pub);
343
	return r;
344
}
345
346
/* Load the certificate associated with the named private key */
347
int
348
sshkey_load_cert(const char *filename, struct sshkey **keyp)
349
{
350
	struct sshkey *pub = NULL;
351
	char *file = NULL;
352
	int r = SSH_ERR_INTERNAL_ERROR;
353
354
	if (keyp != NULL)
355
		*keyp = NULL;
356
357
	if (asprintf(&file, "%s-cert.pub", filename) == -1)
358
		return SSH_ERR_ALLOC_FAIL;
359
360
	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
361
		goto out;
362
	}
363
	if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
364
		goto out;
365
	/* success */
366
	if (keyp != NULL) {
367
		*keyp = pub;
368
		pub = NULL;
369
	}
370
	r = 0;
371
 out:
372
	free(file);
373
	sshkey_free(pub);
374
	return r;
375
}
376
377
/* Load private key and certificate */
378
int
379
sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
380
    struct sshkey **keyp, int *perm_ok)
381
{
382
	struct sshkey *key = NULL, *cert = NULL;
383
	int r;
384
385
	if (keyp != NULL)
386
		*keyp = NULL;
387
388
	switch (type) {
389
#ifdef WITH_OPENSSL
390
	case KEY_RSA:
391
	case KEY_DSA:
392
	case KEY_ECDSA:
393
#endif /* WITH_OPENSSL */
394
	case KEY_ED25519:
395
	case KEY_UNSPEC:
396
		break;
397
	default:
398
		return SSH_ERR_KEY_TYPE_UNKNOWN;
399
	}
400
401
	if ((r = sshkey_load_private_type(type, filename,
402
	    passphrase, &key, NULL, perm_ok)) != 0 ||
403
	    (r = sshkey_load_cert(filename, &cert)) != 0)
404
		goto out;
405
406
	/* Make sure the private key matches the certificate */
407
	if (sshkey_equal_public(key, cert) == 0) {
408
		r = SSH_ERR_KEY_CERT_MISMATCH;
409
		goto out;
410
	}
411
412
	if ((r = sshkey_to_certified(key)) != 0 ||
413
	    (r = sshkey_cert_copy(cert, key)) != 0)
414
		goto out;
415
	r = 0;
416
	if (keyp != NULL) {
417
		*keyp = key;
418
		key = NULL;
419
	}
420
 out:
421
	sshkey_free(key);
422
	sshkey_free(cert);
423
	return r;
424
}
425
426
/*
427
 * Returns success if the specified "key" is listed in the file "filename",
428
 * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
429
 * If "strict_type" is set then the key type must match exactly,
430
 * otherwise a comparison that ignores certficiate data is performed.
431
 * If "check_ca" is set and "key" is a certificate, then its CA key is
432
 * also checked and sshkey_in_file() will return success if either is found.
433
 */
434
int
435
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
436
    int check_ca)
437
{
438
	FILE *f;
439
	char line[SSH_MAX_PUBKEY_BYTES];
440
	char *cp;
441
	u_long linenum = 0;
442
	int r = 0;
443
	struct sshkey *pub = NULL;
444
	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
445
	    strict_type ?  sshkey_equal : sshkey_equal_public;
446
447
	if ((f = fopen(filename, "r")) == NULL)
448
		return SSH_ERR_SYSTEM_ERROR;
449
450
	while (read_keyfile_line(f, filename, line, sizeof(line),
451
	    &linenum) != -1) {
452
		cp = line;
453
454
		/* Skip leading whitespace. */
455
		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
456
			;
457
458
		/* Skip comments and empty lines */
459
		switch (*cp) {
460
		case '#':
461
		case '\n':
462
		case '\0':
463
			continue;
464
		}
465
466
		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
467
			r = SSH_ERR_ALLOC_FAIL;
468
			goto out;
469
		}
470
		if ((r = sshkey_read(pub, &cp)) != 0)
471
			goto out;
472
		if (sshkey_compare(key, pub) ||
473
		    (check_ca && sshkey_is_cert(key) &&
474
		    sshkey_compare(key->cert->signature_key, pub))) {
475
			r = 0;
476
			goto out;
477
		}
478
		sshkey_free(pub);
479
		pub = NULL;
480
	}
481
	r = SSH_ERR_KEY_NOT_FOUND;
482
 out:
483
	sshkey_free(pub);
484
	fclose(f);
485
	return r;
486
}
487
488
/*
489
 * Checks whether the specified key is revoked, returning 0 if not,
490
 * SSH_ERR_KEY_REVOKED if it is or another error code if something
491
 * unexpected happened.
492
 * This will check both the key and, if it is a certificate, its CA key too.
493
 * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
494
 */
495
int
496
sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
497
{
498
	int r;
499
500
	r = ssh_krl_file_contains_key(revoked_keys_file, key);
501
	/* If this was not a KRL to begin with then continue below */
502
	if (r != SSH_ERR_KRL_BAD_MAGIC)
503
		return r;
504
505
	/*
506
	 * If the file is not a KRL or we can't handle KRLs then attempt to
507
	 * parse the file as a flat list of keys.
508
	 */
509
	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
510
	case 0:
511
		/* Key found => revoked */
512
		return SSH_ERR_KEY_REVOKED;
513
	case SSH_ERR_KEY_NOT_FOUND:
514
		/* Key not found => not revoked */
515
		return 0;
516
	default:
517
		/* Some other error occurred */
518
		return r;
519
	}
520
}
521