[BACK]Return to authfile.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/authfile.c, Revision 1.123

1.123   ! deraadt     1: /* $OpenBSD: authfile.c,v 1.122 2016/11/25 23:24:45 djm Exp $ */
1.1       deraadt     2: /*
1.99      markus      3:  * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
1.19      deraadt     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.
1.9       deraadt    24:  */
1.1       deraadt    25:
1.62      stevesk    26:
                     27: #include <sys/types.h>
                     28: #include <sys/stat.h>
1.76      deraadt    29: #include <sys/uio.h>
1.1       deraadt    30:
1.69      stevesk    31: #include <errno.h>
1.68      stevesk    32: #include <fcntl.h>
1.74      stevesk    33: #include <stdio.h>
1.73      stevesk    34: #include <stdlib.h>
1.71      stevesk    35: #include <string.h>
1.70      stevesk    36: #include <unistd.h>
1.110     deraadt    37: #include <limits.h>
1.15      markus     38:
1.25      markus     39: #include "cipher.h"
1.1       deraadt    40: #include "ssh.h"
1.25      markus     41: #include "log.h"
1.27      itojun     42: #include "authfile.h"
1.44      markus     43: #include "rsa.h"
1.60      dtucker    44: #include "misc.h"
1.61      djm        45: #include "atomicio.h"
1.116     markus     46: #include "sshkey.h"
1.107     djm        47: #include "sshbuf.h"
                     48: #include "ssherr.h"
1.108     djm        49: #include "krl.h"
1.1       deraadt    50:
1.88      djm        51: #define MAX_KEY_FILE_SIZE      (1024 * 1024)
                     52:
1.86      djm        53: /* Save a key blob to a file */
                     54: static int
1.107     djm        55: sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
1.86      djm        56: {
1.107     djm        57:        int fd, oerrno;
1.86      djm        58:
1.107     djm        59:        if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
                     60:                return SSH_ERR_SYSTEM_ERROR;
                     61:        if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
                     62:            sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
                     63:                oerrno = errno;
1.86      djm        64:                close(fd);
                     65:                unlink(filename);
1.107     djm        66:                errno = oerrno;
                     67:                return SSH_ERR_SYSTEM_ERROR;
1.86      djm        68:        }
                     69:        close(fd);
1.107     djm        70:        return 0;
1.86      djm        71: }
                     72:
                     73: int
1.107     djm        74: sshkey_save_private(struct sshkey *key, const char *filename,
                     75:     const char *passphrase, const char *comment,
                     76:     int force_new_format, const char *new_format_cipher, int new_format_rounds)
1.86      djm        77: {
1.107     djm        78:        struct sshbuf *keyblob = NULL;
                     79:        int r;
1.86      djm        80:
1.107     djm        81:        if ((keyblob = sshbuf_new()) == NULL)
                     82:                return SSH_ERR_ALLOC_FAIL;
                     83:        if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
                     84:            force_new_format, new_format_cipher, new_format_rounds)) != 0)
1.86      djm        85:                goto out;
1.107     djm        86:        if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
1.86      djm        87:                goto out;
1.107     djm        88:        r = 0;
1.86      djm        89:  out:
1.107     djm        90:        sshbuf_free(keyblob);
                     91:        return r;
1.86      djm        92: }
                     93:
1.88      djm        94: /* Load a key from a fd into a buffer */
                     95: int
1.109     djm        96: sshkey_load_file(int fd, struct sshbuf *blob)
1.86      djm        97: {
1.88      djm        98:        u_char buf[1024];
1.86      djm        99:        size_t len;
1.51      fgsch     100:        struct stat st;
1.122     djm       101:        int r, dontmax = 0;
1.8       markus    102:
1.107     djm       103:        if (fstat(fd, &st) < 0)
                    104:                return SSH_ERR_SYSTEM_ERROR;
1.88      djm       105:        if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
1.107     djm       106:            st.st_size > MAX_KEY_FILE_SIZE)
                    107:                return SSH_ERR_INVALID_FORMAT;
1.122     djm       108:        /*
                    109:         * Pre-allocate the buffer used for the key contents and clamp its
                    110:         * maximum size. This ensures that key contents are never leaked via
                    111:         * implicit realloc() in the sshbuf code.
                    112:         */
                    113:        if ((st.st_mode & S_IFREG) == 0 || st.st_size <= 0) {
1.123   ! deraadt   114:                st.st_size = 64*1024; /* 64k ought to be enough for anybody. :) */
1.122     djm       115:                dontmax = 1;
                    116:        }
                    117:        if ((r = sshbuf_allocate(blob, st.st_size)) != 0 ||
                    118:            (dontmax && (r = sshbuf_set_max_size(blob, st.st_size)) != 0))
                    119:                return r;
1.88      djm       120:        for (;;) {
                    121:                if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
                    122:                        if (errno == EPIPE)
                    123:                                break;
1.107     djm       124:                        r = SSH_ERR_SYSTEM_ERROR;
                    125:                        goto out;
1.88      djm       126:                }
1.107     djm       127:                if ((r = sshbuf_put(blob, buf, len)) != 0)
                    128:                        goto out;
                    129:                if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
                    130:                        r = SSH_ERR_INVALID_FORMAT;
                    131:                        goto out;
1.88      djm       132:                }
                    133:        }
                    134:        if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
1.107     djm       135:            st.st_size != (off_t)sshbuf_len(blob)) {
                    136:                r = SSH_ERR_FILE_CHANGED;
                    137:                goto out;
1.8       markus    138:        }
1.107     djm       139:        r = 0;
1.88      djm       140:
1.107     djm       141:  out:
                    142:        explicit_bzero(buf, sizeof(buf));
                    143:        if (r != 0)
                    144:                sshbuf_reset(blob);
                    145:        return r;
1.86      djm       146: }
1.8       markus    147:
1.106     markus    148: #ifdef WITH_SSH1
1.86      djm       149: /*
                    150:  * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
                    151:  * encountered (the file does not exist or is not readable), and the key
                    152:  * otherwise.
                    153:  */
1.107     djm       154: static int
1.109     djm       155: sshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
1.86      djm       156: {
1.107     djm       157:        struct sshbuf *b = NULL;
                    158:        int r;
1.86      djm       159:
1.121     djm       160:        if (keyp != NULL)
                    161:                *keyp = NULL;
1.107     djm       162:        if (commentp != NULL)
                    163:                *commentp = NULL;
1.8       markus    164:
1.107     djm       165:        if ((b = sshbuf_new()) == NULL)
                    166:                return SSH_ERR_ALLOC_FAIL;
1.109     djm       167:        if ((r = sshkey_load_file(fd, b)) != 0)
1.107     djm       168:                goto out;
                    169:        if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
                    170:                goto out;
                    171:        r = 0;
                    172:  out:
                    173:        sshbuf_free(b);
                    174:        return r;
1.1       deraadt   175: }
1.107     djm       176: #endif /* WITH_SSH1 */
1.1       deraadt   177:
1.107     djm       178: /* XXX remove error() calls from here? */
1.63      dtucker   179: int
1.107     djm       180: sshkey_perm_ok(int fd, const char *filename)
1.15      markus    181: {
                    182:        struct stat st;
                    183:
1.38      markus    184:        if (fstat(fd, &st) < 0)
1.107     djm       185:                return SSH_ERR_SYSTEM_ERROR;
1.38      markus    186:        /*
                    187:         * if a key owned by the user is accessed, then we check the
                    188:         * permissions of the file. if the key owned by a different user,
                    189:         * then we don't care.
                    190:         */
                    191:        if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
1.15      markus    192:                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
                    193:                error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
                    194:                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1.38      markus    195:                error("Permissions 0%3.3o for '%s' are too open.",
1.54      djm       196:                    (u_int)st.st_mode & 0777, filename);
1.114     djm       197:                error("It is required that your private key files are NOT accessible by others.");
1.29      markus    198:                error("This private key will be ignored.");
1.107     djm       199:                return SSH_ERR_KEY_BAD_PERMISSIONS;
1.15      markus    200:        }
1.107     djm       201:        return 0;
1.29      markus    202: }
                    203:
1.107     djm       204: /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
                    205: int
                    206: sshkey_load_private_type(int type, const char *filename, const char *passphrase,
                    207:     struct sshkey **keyp, char **commentp, int *perm_ok)
1.86      djm       208: {
1.107     djm       209:        int fd, r;
1.99      markus    210:
1.121     djm       211:        if (keyp != NULL)
                    212:                *keyp = NULL;
1.107     djm       213:        if (commentp != NULL)
                    214:                *commentp = NULL;
1.86      djm       215:
1.107     djm       216:        if ((fd = open(filename, O_RDONLY)) < 0) {
1.78      dtucker   217:                if (perm_ok != NULL)
                    218:                        *perm_ok = 0;
1.107     djm       219:                return SSH_ERR_SYSTEM_ERROR;
1.78      dtucker   220:        }
1.107     djm       221:        if (sshkey_perm_ok(fd, filename) != 0) {
1.67      dtucker   222:                if (perm_ok != NULL)
                    223:                        *perm_ok = 0;
1.107     djm       224:                r = SSH_ERR_KEY_BAD_PERMISSIONS;
                    225:                goto out;
1.29      markus    226:        }
1.67      dtucker   227:        if (perm_ok != NULL)
                    228:                *perm_ok = 1;
1.86      djm       229:
1.109     djm       230:        r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
                    231:  out:
                    232:        close(fd);
                    233:        return r;
                    234: }
                    235:
                    236: int
                    237: sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
                    238:     struct sshkey **keyp, char **commentp)
                    239: {
                    240:        struct sshbuf *buffer = NULL;
                    241:        int r;
                    242:
1.121     djm       243:        if (keyp != NULL)
                    244:                *keyp = NULL;
1.107     djm       245:        if ((buffer = sshbuf_new()) == NULL) {
                    246:                r = SSH_ERR_ALLOC_FAIL;
                    247:                goto out;
1.15      markus    248:        }
1.109     djm       249:        if ((r = sshkey_load_file(fd, buffer)) != 0 ||
                    250:            (r = sshkey_parse_private_fileblob_type(buffer, type,
                    251:            passphrase, keyp, commentp)) != 0)
1.107     djm       252:                goto out;
1.109     djm       253:
                    254:        /* success */
1.107     djm       255:        r = 0;
                    256:  out:
1.120     mmcc      257:        sshbuf_free(buffer);
1.107     djm       258:        return r;
1.29      markus    259: }
                    260:
1.107     djm       261: /* XXX this is almost identical to sshkey_load_private_type() */
                    262: int
                    263: sshkey_load_private(const char *filename, const char *passphrase,
                    264:     struct sshkey **keyp, char **commentp)
1.88      djm       265: {
1.107     djm       266:        struct sshbuf *buffer = NULL;
                    267:        int r, fd;
1.88      djm       268:
1.121     djm       269:        if (keyp != NULL)
                    270:                *keyp = NULL;
1.107     djm       271:        if (commentp != NULL)
                    272:                *commentp = NULL;
1.88      djm       273:
1.107     djm       274:        if ((fd = open(filename, O_RDONLY)) < 0)
                    275:                return SSH_ERR_SYSTEM_ERROR;
                    276:        if (sshkey_perm_ok(fd, filename) != 0) {
                    277:                r = SSH_ERR_KEY_BAD_PERMISSIONS;
                    278:                goto out;
1.29      markus    279:        }
1.86      djm       280:
1.107     djm       281:        if ((buffer = sshbuf_new()) == NULL) {
                    282:                r = SSH_ERR_ALLOC_FAIL;
                    283:                goto out;
1.86      djm       284:        }
1.109     djm       285:        if ((r = sshkey_load_file(fd, buffer)) != 0 ||
1.117     tim       286:            (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
                    287:            commentp)) != 0)
1.107     djm       288:                goto out;
                    289:        r = 0;
                    290:  out:
1.86      djm       291:        close(fd);
1.120     mmcc      292:        sshbuf_free(buffer);
1.107     djm       293:        return r;
1.18      markus    294: }
                    295:
1.37      itojun    296: static int
1.107     djm       297: sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
1.18      markus    298: {
                    299:        FILE *f;
1.59      dtucker   300:        char line[SSH_MAX_PUBKEY_BYTES];
1.18      markus    301:        char *cp;
1.60      dtucker   302:        u_long linenum = 0;
1.107     djm       303:        int r;
1.18      markus    304:
1.107     djm       305:        if (commentp != NULL)
                    306:                *commentp = NULL;
                    307:        if ((f = fopen(filename, "r")) == NULL)
                    308:                return SSH_ERR_SYSTEM_ERROR;
                    309:        while (read_keyfile_line(f, filename, line, sizeof(line),
                    310:                    &linenum) != -1) {
                    311:                cp = line;
                    312:                switch (*cp) {
                    313:                case '#':
                    314:                case '\n':
                    315:                case '\0':
                    316:                        continue;
                    317:                }
                    318:                /* Abort loading if this looks like a private key */
                    319:                if (strncmp(cp, "-----BEGIN", 10) == 0 ||
                    320:                    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
                    321:                        break;
                    322:                /* Skip leading whitespace. */
                    323:                for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
                    324:                        ;
                    325:                if (*cp) {
                    326:                        if ((r = sshkey_read(k, &cp)) == 0) {
                    327:                                cp[strcspn(cp, "\r\n")] = '\0';
                    328:                                if (commentp) {
                    329:                                        *commentp = strdup(*cp ?
                    330:                                            cp : filename);
                    331:                                        if (*commentp == NULL)
                    332:                                                r = SSH_ERR_ALLOC_FAIL;
1.18      markus    333:                                }
1.107     djm       334:                                fclose(f);
                    335:                                return r;
1.18      markus    336:                        }
                    337:                }
                    338:        }
1.107     djm       339:        fclose(f);
                    340:        return SSH_ERR_INVALID_FORMAT;
1.18      markus    341: }
                    342:
1.29      markus    343: /* load public key from ssh v1 private or any pubkey file */
1.107     djm       344: int
                    345: sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
1.18      markus    346: {
1.107     djm       347:        struct sshkey *pub = NULL;
1.110     deraadt   348:        char file[PATH_MAX];
1.107     djm       349:        int r, fd;
1.18      markus    350:
1.107     djm       351:        if (keyp != NULL)
                    352:                *keyp = NULL;
                    353:        if (commentp != NULL)
                    354:                *commentp = NULL;
                    355:
1.111     djm       356:        /* XXX should load file once and attempt to parse each format */
                    357:
1.107     djm       358:        if ((fd = open(filename, O_RDONLY)) < 0)
                    359:                goto skip;
1.106     markus    360: #ifdef WITH_SSH1
1.53      markus    361:        /* try rsa1 private key */
1.109     djm       362:        r = sshkey_load_public_rsa1(fd, keyp, commentp);
1.107     djm       363:        close(fd);
                    364:        switch (r) {
                    365:        case SSH_ERR_INTERNAL_ERROR:
                    366:        case SSH_ERR_ALLOC_FAIL:
                    367:        case SSH_ERR_INVALID_ARGUMENT:
                    368:        case SSH_ERR_SYSTEM_ERROR:
                    369:        case 0:
                    370:                return r;
                    371:        }
1.113     djm       372: #else /* WITH_SSH1 */
                    373:        close(fd);
1.107     djm       374: #endif /* WITH_SSH1 */
                    375:
                    376:        /* try ssh2 public key */
                    377:        if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
                    378:                return SSH_ERR_ALLOC_FAIL;
                    379:        if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
                    380:                if (keyp != NULL)
                    381:                        *keyp = pub;
                    382:                return 0;
                    383:        }
                    384:        sshkey_free(pub);
1.53      markus    385:
1.107     djm       386: #ifdef WITH_SSH1
1.53      markus    387:        /* try rsa1 public key */
1.107     djm       388:        if ((pub = sshkey_new(KEY_RSA1)) == NULL)
                    389:                return SSH_ERR_ALLOC_FAIL;
                    390:        if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
                    391:                if (keyp != NULL)
                    392:                        *keyp = pub;
                    393:                return 0;
                    394:        }
                    395:        sshkey_free(pub);
                    396: #endif /* WITH_SSH1 */
1.53      markus    397:
1.107     djm       398:  skip:
                    399:        /* try .pub suffix */
                    400:        if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
                    401:                return SSH_ERR_ALLOC_FAIL;
                    402:        r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */
1.29      markus    403:        if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
                    404:            (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
1.107     djm       405:            (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
                    406:                if (keyp != NULL)
                    407:                        *keyp = pub;
                    408:                return 0;
                    409:        }
                    410:        sshkey_free(pub);
1.111     djm       411:
1.107     djm       412:        return r;
1.81      djm       413: }
                    414:
                    415: /* Load the certificate associated with the named private key */
1.107     djm       416: int
                    417: sshkey_load_cert(const char *filename, struct sshkey **keyp)
1.81      djm       418: {
1.107     djm       419:        struct sshkey *pub = NULL;
                    420:        char *file = NULL;
                    421:        int r = SSH_ERR_INTERNAL_ERROR;
                    422:
1.121     djm       423:        if (keyp != NULL)
                    424:                *keyp = NULL;
1.81      djm       425:
1.107     djm       426:        if (asprintf(&file, "%s-cert.pub", filename) == -1)
                    427:                return SSH_ERR_ALLOC_FAIL;
                    428:
                    429:        if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
                    430:                goto out;
                    431:        }
                    432:        if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
                    433:                goto out;
1.121     djm       434:        /* success */
                    435:        if (keyp != NULL) {
                    436:                *keyp = pub;
                    437:                pub = NULL;
                    438:        }
1.107     djm       439:        r = 0;
                    440:  out:
1.118     mmcc      441:        free(file);
1.119     mmcc      442:        sshkey_free(pub);
1.107     djm       443:        return r;
1.81      djm       444: }
                    445:
                    446: /* Load private key and certificate */
1.107     djm       447: int
                    448: sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
                    449:     struct sshkey **keyp, int *perm_ok)
1.81      djm       450: {
1.107     djm       451:        struct sshkey *key = NULL, *cert = NULL;
                    452:        int r;
                    453:
1.121     djm       454:        if (keyp != NULL)
                    455:                *keyp = NULL;
1.81      djm       456:
                    457:        switch (type) {
1.106     markus    458: #ifdef WITH_OPENSSL
1.81      djm       459:        case KEY_RSA:
                    460:        case KEY_DSA:
1.83      djm       461:        case KEY_ECDSA:
1.116     markus    462: #endif /* WITH_OPENSSL */
1.101     djm       463:        case KEY_ED25519:
1.107     djm       464:        case KEY_UNSPEC:
1.81      djm       465:                break;
                    466:        default:
1.107     djm       467:                return SSH_ERR_KEY_TYPE_UNKNOWN;
1.81      djm       468:        }
                    469:
1.107     djm       470:        if ((r = sshkey_load_private_type(type, filename,
                    471:            passphrase, &key, NULL, perm_ok)) != 0 ||
                    472:            (r = sshkey_load_cert(filename, &cert)) != 0)
                    473:                goto out;
1.81      djm       474:
                    475:        /* Make sure the private key matches the certificate */
1.107     djm       476:        if (sshkey_equal_public(key, cert) == 0) {
                    477:                r = SSH_ERR_KEY_CERT_MISMATCH;
                    478:                goto out;
1.81      djm       479:        }
                    480:
1.115     djm       481:        if ((r = sshkey_to_certified(key)) != 0 ||
1.107     djm       482:            (r = sshkey_cert_copy(cert, key)) != 0)
                    483:                goto out;
                    484:        r = 0;
1.121     djm       485:        if (keyp != NULL) {
                    486:                *keyp = key;
                    487:                key = NULL;
                    488:        }
1.107     djm       489:  out:
1.119     mmcc      490:        sshkey_free(key);
                    491:        sshkey_free(cert);
1.107     djm       492:        return r;
1.1       deraadt   493: }
1.80      djm       494:
                    495: /*
1.107     djm       496:  * Returns success if the specified "key" is listed in the file "filename",
                    497:  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
1.108     djm       498:  * If "strict_type" is set then the key type must match exactly,
1.80      djm       499:  * otherwise a comparison that ignores certficiate data is performed.
1.108     djm       500:  * If "check_ca" is set and "key" is a certificate, then its CA key is
                    501:  * also checked and sshkey_in_file() will return success if either is found.
1.80      djm       502:  */
                    503: int
1.108     djm       504: sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
                    505:     int check_ca)
1.80      djm       506: {
                    507:        FILE *f;
                    508:        char line[SSH_MAX_PUBKEY_BYTES];
                    509:        char *cp;
                    510:        u_long linenum = 0;
1.107     djm       511:        int r = 0;
                    512:        struct sshkey *pub = NULL;
                    513:        int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
                    514:            strict_type ?  sshkey_equal : sshkey_equal_public;
1.80      djm       515:
1.108     djm       516:        if ((f = fopen(filename, "r")) == NULL)
                    517:                return SSH_ERR_SYSTEM_ERROR;
1.80      djm       518:
                    519:        while (read_keyfile_line(f, filename, line, sizeof(line),
1.107     djm       520:            &linenum) != -1) {
1.80      djm       521:                cp = line;
                    522:
                    523:                /* Skip leading whitespace. */
                    524:                for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
                    525:                        ;
                    526:
                    527:                /* Skip comments and empty lines */
                    528:                switch (*cp) {
                    529:                case '#':
                    530:                case '\n':
                    531:                case '\0':
                    532:                        continue;
                    533:                }
                    534:
1.107     djm       535:                if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
                    536:                        r = SSH_ERR_ALLOC_FAIL;
                    537:                        goto out;
1.80      djm       538:                }
1.107     djm       539:                if ((r = sshkey_read(pub, &cp)) != 0)
                    540:                        goto out;
1.108     djm       541:                if (sshkey_compare(key, pub) ||
                    542:                    (check_ca && sshkey_is_cert(key) &&
                    543:                    sshkey_compare(key->cert->signature_key, pub))) {
1.107     djm       544:                        r = 0;
                    545:                        goto out;
1.80      djm       546:                }
1.107     djm       547:                sshkey_free(pub);
                    548:                pub = NULL;
1.80      djm       549:        }
1.107     djm       550:        r = SSH_ERR_KEY_NOT_FOUND;
                    551:  out:
1.119     mmcc      552:        sshkey_free(pub);
1.80      djm       553:        fclose(f);
1.107     djm       554:        return r;
1.108     djm       555: }
                    556:
                    557: /*
                    558:  * Checks whether the specified key is revoked, returning 0 if not,
                    559:  * SSH_ERR_KEY_REVOKED if it is or another error code if something
                    560:  * unexpected happened.
                    561:  * This will check both the key and, if it is a certificate, its CA key too.
                    562:  * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
                    563:  */
                    564: int
                    565: sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
                    566: {
                    567:        int r;
                    568:
                    569:        r = ssh_krl_file_contains_key(revoked_keys_file, key);
                    570:        /* If this was not a KRL to begin with then continue below */
                    571:        if (r != SSH_ERR_KRL_BAD_MAGIC)
                    572:                return r;
                    573:
                    574:        /*
                    575:         * If the file is not a KRL or we can't handle KRLs then attempt to
                    576:         * parse the file as a flat list of keys.
                    577:         */
                    578:        switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
                    579:        case 0:
                    580:                /* Key found => revoked */
                    581:                return SSH_ERR_KEY_REVOKED;
                    582:        case SSH_ERR_KEY_NOT_FOUND:
                    583:                /* Key not found => not revoked */
                    584:                return 0;
                    585:        default:
                    586:                /* Some other error occurred */
                    587:                return r;
                    588:        }
1.80      djm       589: }
1.107     djm       590: