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

Annotation of src/usr.bin/ssh/sshsig.c, Revision 1.21

1.21    ! djm         1: /* $OpenBSD: sshsig.c,v 1.20 2021/01/31 10:50:10 dtucker Exp $ */
1.1       djm         2: /*
                      3:  * Copyright (c) 2019 Google LLC
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17:
                     18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <stdarg.h>
                     21: #include <errno.h>
                     22: #include <string.h>
                     23: #include <unistd.h>
                     24:
                     25: #include "authfd.h"
                     26: #include "authfile.h"
                     27: #include "log.h"
                     28: #include "misc.h"
                     29: #include "sshbuf.h"
                     30: #include "sshsig.h"
                     31: #include "ssherr.h"
                     32: #include "sshkey.h"
                     33: #include "match.h"
                     34: #include "digest.h"
                     35:
                     36: #define SIG_VERSION            0x01
                     37: #define MAGIC_PREAMBLE         "SSHSIG"
                     38: #define MAGIC_PREAMBLE_LEN     (sizeof(MAGIC_PREAMBLE) - 1)
                     39: #define BEGIN_SIGNATURE                "-----BEGIN SSH SIGNATURE-----\n"
                     40: #define END_SIGNATURE          "-----END SSH SIGNATURE-----"
                     41: #define RSA_SIGN_ALG           "rsa-sha2-512" /* XXX maybe make configurable */
                     42: #define RSA_SIGN_ALLOWED       "rsa-sha2-512,rsa-sha2-256"
                     43: #define HASHALG_DEFAULT                "sha512" /* XXX maybe make configurable */
                     44: #define HASHALG_ALLOWED                "sha256,sha512"
                     45:
                     46: int
                     47: sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
                     48: {
                     49:        struct sshbuf *buf = NULL;
                     50:        int r = SSH_ERR_INTERNAL_ERROR;
                     51:
                     52:        *out = NULL;
                     53:
                     54:        if ((buf = sshbuf_new()) == NULL) {
1.18      djm        55:                error_f("sshbuf_new failed");
1.1       djm        56:                r = SSH_ERR_ALLOC_FAIL;
                     57:                goto out;
                     58:        }
                     59:
                     60:        if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
                     61:            sizeof(BEGIN_SIGNATURE)-1)) != 0) {
1.18      djm        62:                error_fr(r, "sshbuf_putf");
1.1       djm        63:                goto out;
                     64:        }
                     65:
                     66:        if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
1.18      djm        67:                error_fr(r, "base64 encode signature");
1.1       djm        68:                goto out;
                     69:        }
                     70:
                     71:        if ((r = sshbuf_put(buf, END_SIGNATURE,
                     72:            sizeof(END_SIGNATURE)-1)) != 0 ||
                     73:            (r = sshbuf_put_u8(buf, '\n')) != 0) {
1.18      djm        74:                error_fr(r, "sshbuf_put");
1.1       djm        75:                goto out;
                     76:        }
                     77:        /* success */
                     78:        *out = buf;
                     79:        buf = NULL; /* transferred */
                     80:        r = 0;
                     81:  out:
                     82:        sshbuf_free(buf);
                     83:        return r;
                     84: }
                     85:
                     86: int
                     87: sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
                     88: {
                     89:        int r;
                     90:        size_t eoffset = 0;
                     91:        struct sshbuf *buf = NULL;
                     92:        struct sshbuf *sbuf = NULL;
                     93:        char *b64 = NULL;
                     94:
                     95:        if ((sbuf = sshbuf_fromb(sig)) == NULL) {
1.18      djm        96:                error_f("sshbuf_fromb failed");
1.1       djm        97:                return SSH_ERR_ALLOC_FAIL;
                     98:        }
                     99:
                    100:        if ((r = sshbuf_cmp(sbuf, 0,
                    101:            BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
                    102:                error("Couldn't parse signature: missing header");
                    103:                goto done;
                    104:        }
                    105:
                    106:        if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
1.18      djm       107:                error_fr(r, "consume");
1.1       djm       108:                goto done;
                    109:        }
                    110:
                    111:        if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE,
                    112:            sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) {
                    113:                error("Couldn't parse signature: missing footer");
                    114:                goto done;
                    115:        }
                    116:
                    117:        if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) {
1.18      djm       118:                error_fr(r, "consume");
1.1       djm       119:                goto done;
                    120:        }
                    121:
                    122:        if ((b64 = sshbuf_dup_string(sbuf)) == NULL) {
1.18      djm       123:                error_f("sshbuf_dup_string failed");
1.1       djm       124:                r = SSH_ERR_ALLOC_FAIL;
                    125:                goto done;
                    126:        }
                    127:
                    128:        if ((buf = sshbuf_new()) == NULL) {
1.18      djm       129:                error_f("sshbuf_new() failed");
1.1       djm       130:                r = SSH_ERR_ALLOC_FAIL;
                    131:                goto done;
                    132:        }
                    133:
                    134:        if ((r = sshbuf_b64tod(buf, b64)) != 0) {
1.18      djm       135:                error_fr(r, "decode base64");
1.1       djm       136:                goto done;
                    137:        }
                    138:
                    139:        /* success */
                    140:        *out = buf;
                    141:        r = 0;
                    142:        buf = NULL; /* transferred */
                    143: done:
                    144:        sshbuf_free(buf);
                    145:        sshbuf_free(sbuf);
                    146:        free(b64);
                    147:        return r;
                    148: }
                    149:
                    150: static int
                    151: sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
1.16      djm       152:     const char *sk_provider, const char *sk_pin, const struct sshbuf *h_message,
1.7       djm       153:     const char *sig_namespace, struct sshbuf **out,
                    154:     sshsig_signer *signer, void *signer_ctx)
1.1       djm       155: {
                    156:        int r;
                    157:        size_t slen = 0;
                    158:        u_char *sig = NULL;
                    159:        struct sshbuf *blob = NULL;
                    160:        struct sshbuf *tosign = NULL;
                    161:        const char *sign_alg = NULL;
                    162:
                    163:        if ((tosign = sshbuf_new()) == NULL ||
                    164:            (blob = sshbuf_new()) == NULL) {
1.18      djm       165:                error_f("sshbuf_new failed");
1.1       djm       166:                r = SSH_ERR_ALLOC_FAIL;
                    167:                goto done;
                    168:        }
                    169:
                    170:        if ((r = sshbuf_put(tosign, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
                    171:            (r = sshbuf_put_cstring(tosign, sig_namespace)) != 0 ||
                    172:            (r = sshbuf_put_string(tosign, NULL, 0)) != 0 || /* reserved */
                    173:            (r = sshbuf_put_cstring(tosign, hashalg)) != 0 ||
1.6       djm       174:            (r = sshbuf_put_stringb(tosign, h_message)) != 0) {
1.18      djm       175:                error_fr(r, "assemble message to sign");
1.1       djm       176:                goto done;
                    177:        }
                    178:
                    179:        /* If using RSA keys then default to a good signature algorithm */
                    180:        if (sshkey_type_plain(key->type) == KEY_RSA)
                    181:                sign_alg = RSA_SIGN_ALG;
                    182:
                    183:        if (signer != NULL) {
                    184:                if ((r = signer(key, &sig, &slen,
                    185:                    sshbuf_ptr(tosign), sshbuf_len(tosign),
1.16      djm       186:                    sign_alg, sk_provider, sk_pin, 0, signer_ctx)) != 0) {
1.18      djm       187:                        error_r(r, "Couldn't sign message (signer)");
1.1       djm       188:                        goto done;
                    189:                }
                    190:        } else {
                    191:                if ((r = sshkey_sign(key, &sig, &slen,
                    192:                    sshbuf_ptr(tosign), sshbuf_len(tosign),
1.16      djm       193:                    sign_alg, sk_provider, sk_pin, 0)) != 0) {
1.18      djm       194:                        error_r(r, "Couldn't sign message");
1.1       djm       195:                        goto done;
                    196:                }
                    197:        }
                    198:
                    199:        if ((r = sshbuf_put(blob, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
                    200:            (r = sshbuf_put_u32(blob, SIG_VERSION)) != 0 ||
                    201:            (r = sshkey_puts(key, blob)) != 0 ||
                    202:            (r = sshbuf_put_cstring(blob, sig_namespace)) != 0 ||
                    203:            (r = sshbuf_put_string(blob, NULL, 0)) != 0 || /* reserved */
                    204:            (r = sshbuf_put_cstring(blob, hashalg)) != 0 ||
                    205:            (r = sshbuf_put_string(blob, sig, slen)) != 0) {
1.18      djm       206:                error_fr(r, "assemble signature object");
1.1       djm       207:                goto done;
                    208:        }
                    209:
1.12      markus    210:        if (out != NULL) {
                    211:                *out = blob;
                    212:                blob = NULL;
                    213:        }
1.1       djm       214:        r = 0;
                    215: done:
                    216:        free(sig);
                    217:        sshbuf_free(blob);
                    218:        sshbuf_free(tosign);
                    219:        return r;
                    220: }
                    221:
                    222: /* Check preamble and version. */
                    223: static int
                    224: sshsig_parse_preamble(struct sshbuf *buf)
                    225: {
                    226:        int r = SSH_ERR_INTERNAL_ERROR;
                    227:        uint32_t sversion;
                    228:
                    229:        if ((r = sshbuf_cmp(buf, 0, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
                    230:            (r = sshbuf_consume(buf, (sizeof(MAGIC_PREAMBLE)-1))) != 0 ||
                    231:            (r = sshbuf_get_u32(buf, &sversion)) != 0) {
                    232:                error("Couldn't verify signature: invalid format");
                    233:                return r;
                    234:        }
                    235:
1.2       djm       236:        if (sversion > SIG_VERSION) {
1.1       djm       237:                error("Signature version %lu is larger than supported "
                    238:                    "version %u", (unsigned long)sversion, SIG_VERSION);
                    239:                return SSH_ERR_INVALID_FORMAT;
                    240:        }
                    241:        return 0;
                    242: }
                    243:
                    244: static int
                    245: sshsig_check_hashalg(const char *hashalg)
                    246: {
1.2       djm       247:        if (hashalg == NULL ||
                    248:            match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1)
1.1       djm       249:                return 0;
1.18      djm       250:        error_f("unsupported hash algorithm \"%.100s\"", hashalg);
1.1       djm       251:        return SSH_ERR_SIGN_ALG_UNSUPPORTED;
                    252: }
                    253:
                    254: static int
                    255: sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp)
                    256: {
                    257:        struct sshbuf *buf = NULL;
                    258:        char *hashalg = NULL;
                    259:        int r = SSH_ERR_INTERNAL_ERROR;
                    260:
                    261:        if (hashalgp != NULL)
                    262:                *hashalgp = NULL;
                    263:        if ((buf = sshbuf_fromb(signature)) == NULL)
                    264:                return SSH_ERR_ALLOC_FAIL;
                    265:        if ((r = sshsig_parse_preamble(buf)) != 0)
                    266:                goto done;
                    267:        if ((r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
                    268:            (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
                    269:            (r = sshbuf_get_string(buf, NULL, NULL)) != 0 ||
                    270:            (r = sshbuf_get_cstring(buf, &hashalg, NULL)) != 0 ||
                    271:            (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0) {
1.18      djm       272:                error_fr(r, "parse signature object");
1.1       djm       273:                goto done;
                    274:        }
                    275:
                    276:        /* success */
                    277:        r = 0;
                    278:        *hashalgp = hashalg;
                    279:        hashalg = NULL;
                    280:  done:
                    281:        free(hashalg);
                    282:        sshbuf_free(buf);
                    283:        return r;
                    284: }
                    285:
                    286: static int
                    287: sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg,
                    288:     const struct sshbuf *h_message, const char *expect_namespace,
1.8       djm       289:     struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details)
1.1       djm       290: {
                    291:        int r = SSH_ERR_INTERNAL_ERROR;
                    292:        struct sshbuf *buf = NULL, *toverify = NULL;
                    293:        struct sshkey *key = NULL;
                    294:        const u_char *sig;
                    295:        char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL;
                    296:        size_t siglen;
                    297:
1.18      djm       298:        debug_f("verify message length %zu", sshbuf_len(h_message));
1.8       djm       299:        if (sig_details != NULL)
                    300:                *sig_details = NULL;
1.1       djm       301:        if (sign_keyp != NULL)
                    302:                *sign_keyp = NULL;
                    303:
                    304:        if ((toverify = sshbuf_new()) == NULL) {
1.18      djm       305:                error_f("sshbuf_new failed");
1.1       djm       306:                r = SSH_ERR_ALLOC_FAIL;
                    307:                goto done;
                    308:        }
                    309:        if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE,
                    310:            MAGIC_PREAMBLE_LEN)) != 0 ||
                    311:            (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 ||
                    312:            (r = sshbuf_put_string(toverify, NULL, 0)) != 0 || /* reserved */
                    313:            (r = sshbuf_put_cstring(toverify, hashalg)) != 0 ||
1.6       djm       314:            (r = sshbuf_put_stringb(toverify, h_message)) != 0) {
1.18      djm       315:                error_fr(r, "assemble message to verify");
1.1       djm       316:                goto done;
                    317:        }
                    318:
                    319:        if ((r = sshsig_parse_preamble(signature)) != 0)
                    320:                goto done;
                    321:
                    322:        if ((r = sshkey_froms(signature, &key)) != 0 ||
                    323:            (r = sshbuf_get_cstring(signature, &got_namespace, NULL)) != 0 ||
                    324:            (r = sshbuf_get_string(signature, NULL, NULL)) != 0 ||
                    325:            (r = sshbuf_get_cstring(signature, &sig_hashalg, NULL)) != 0 ||
                    326:            (r = sshbuf_get_string_direct(signature, &sig, &siglen)) != 0) {
1.18      djm       327:                error_fr(r, "parse signature object");
1.1       djm       328:                goto done;
                    329:        }
                    330:
                    331:        if (sshbuf_len(signature) != 0) {
                    332:                error("Signature contains trailing data");
                    333:                r = SSH_ERR_INVALID_FORMAT;
                    334:                goto done;
                    335:        }
                    336:
                    337:        if (strcmp(expect_namespace, got_namespace) != 0) {
                    338:                error("Couldn't verify signature: namespace does not match");
1.18      djm       339:                debug_f("expected namespace \"%s\" received \"%s\"",
                    340:                    expect_namespace, got_namespace);
1.1       djm       341:                r = SSH_ERR_SIGNATURE_INVALID;
                    342:                goto done;
                    343:        }
                    344:        if (strcmp(hashalg, sig_hashalg) != 0) {
                    345:                error("Couldn't verify signature: hash algorithm mismatch");
1.18      djm       346:                debug_f("expected algorithm \"%s\" received \"%s\"",
                    347:                    hashalg, sig_hashalg);
1.1       djm       348:                r = SSH_ERR_SIGNATURE_INVALID;
                    349:                goto done;
                    350:        }
                    351:        /* Ensure that RSA keys use an acceptable signature algorithm */
                    352:        if (sshkey_type_plain(key->type) == KEY_RSA) {
                    353:                if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0) {
1.18      djm       354:                        error_r(r, "Couldn't verify signature: unable to get "
                    355:                            "signature type");
1.1       djm       356:                        goto done;
                    357:                }
                    358:                if (match_pattern_list(sigtype, RSA_SIGN_ALLOWED, 0) != 1) {
                    359:                        error("Couldn't verify signature: unsupported RSA "
                    360:                            "signature algorithm %s", sigtype);
                    361:                        r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
                    362:                        goto done;
                    363:                }
                    364:        }
                    365:        if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify),
1.8       djm       366:            sshbuf_len(toverify), NULL, 0, sig_details)) != 0) {
1.18      djm       367:                error_r(r, "Signature verification failed");
1.1       djm       368:                goto done;
                    369:        }
                    370:
                    371:        /* success */
                    372:        r = 0;
                    373:        if (sign_keyp != NULL) {
                    374:                *sign_keyp = key;
                    375:                key = NULL; /* transferred */
                    376:        }
                    377: done:
                    378:        free(got_namespace);
                    379:        free(sigtype);
                    380:        free(sig_hashalg);
                    381:        sshbuf_free(buf);
                    382:        sshbuf_free(toverify);
                    383:        sshkey_free(key);
                    384:        return r;
                    385: }
                    386:
1.2       djm       387: static int
                    388: hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
1.1       djm       389: {
1.2       djm       390:        char *hex, hash[SSH_DIGEST_MAX_LENGTH];
                    391:        int alg, r = SSH_ERR_INTERNAL_ERROR;
1.1       djm       392:        struct sshbuf *b = NULL;
                    393:
1.2       djm       394:        *bp = NULL;
                    395:        memset(hash, 0, sizeof(hash));
1.1       djm       396:
                    397:        if ((r = sshsig_check_hashalg(hashalg)) != 0)
                    398:                return r;
                    399:        if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
1.18      djm       400:                error_f("can't look up hash algorithm %s", hashalg);
1.1       djm       401:                return SSH_ERR_INTERNAL_ERROR;
                    402:        }
1.2       djm       403:        if ((r = ssh_digest_buffer(alg, m, hash, sizeof(hash))) != 0) {
1.18      djm       404:                error_fr(r, "ssh_digest_buffer");
1.1       djm       405:                return r;
                    406:        }
1.2       djm       407:        if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
1.18      djm       408:                debug3_f("final hash: %s", hex);
1.2       djm       409:                freezero(hex, strlen(hex));
                    410:        }
                    411:        if ((b = sshbuf_new()) == NULL) {
1.1       djm       412:                r = SSH_ERR_ALLOC_FAIL;
                    413:                goto out;
                    414:        }
1.2       djm       415:        if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
1.18      djm       416:                error_fr(r, "sshbuf_put");
1.2       djm       417:                goto out;
                    418:        }
                    419:        *bp = b;
                    420:        b = NULL; /* transferred */
                    421:        /* success */
                    422:        r = 0;
                    423:  out:
                    424:        sshbuf_free(b);
                    425:        explicit_bzero(hash, sizeof(hash));
1.12      markus    426:        return r;
1.2       djm       427: }
                    428:
                    429: int
1.16      djm       430: sshsig_signb(struct sshkey *key, const char *hashalg,
                    431:     const char *sk_provider, const char *sk_pin,
1.2       djm       432:     const struct sshbuf *message, const char *sig_namespace,
                    433:     struct sshbuf **out, sshsig_signer *signer, void *signer_ctx)
                    434: {
                    435:        struct sshbuf *b = NULL;
                    436:        int r = SSH_ERR_INTERNAL_ERROR;
                    437:
                    438:        if (hashalg == NULL)
                    439:                hashalg = HASHALG_DEFAULT;
                    440:        if (out != NULL)
                    441:                *out = NULL;
                    442:        if ((r = hash_buffer(message, hashalg, &b)) != 0) {
1.18      djm       443:                error_fr(r, "hash buffer");
1.2       djm       444:                goto out;
                    445:        }
1.16      djm       446:        if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
1.7       djm       447:            sig_namespace, out, signer, signer_ctx)) != 0)
1.1       djm       448:                goto out;
                    449:        /* success */
                    450:        r = 0;
                    451:  out:
                    452:        sshbuf_free(b);
                    453:        return r;
                    454: }
                    455:
                    456: int
1.2       djm       457: sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message,
1.8       djm       458:     const char *expect_namespace, struct sshkey **sign_keyp,
                    459:     struct sshkey_sig_details **sig_details)
1.1       djm       460: {
                    461:        struct sshbuf *b = NULL;
1.2       djm       462:        int r = SSH_ERR_INTERNAL_ERROR;
1.1       djm       463:        char *hashalg = NULL;
                    464:
1.8       djm       465:        if (sig_details != NULL)
                    466:                *sig_details = NULL;
1.1       djm       467:        if (sign_keyp != NULL)
                    468:                *sign_keyp = NULL;
                    469:        if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
                    470:                return r;
1.18      djm       471:        debug_f("signature made with hash \"%s\"", hashalg);
1.2       djm       472:        if ((r = hash_buffer(message, hashalg, &b)) != 0) {
1.18      djm       473:                error_fr(r, "hash buffer");
1.1       djm       474:                goto out;
                    475:        }
                    476:        if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
1.8       djm       477:            sign_keyp, sig_details)) != 0)
1.1       djm       478:                goto out;
                    479:        /* success */
                    480:        r = 0;
                    481:  out:
                    482:        sshbuf_free(b);
                    483:        free(hashalg);
                    484:        return r;
                    485: }
                    486:
                    487: static int
1.2       djm       488: hash_file(int fd, const char *hashalg, struct sshbuf **bp)
1.1       djm       489: {
1.2       djm       490:        char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH];
1.1       djm       491:        ssize_t n, total = 0;
                    492:        struct ssh_digest_ctx *ctx;
1.2       djm       493:        int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR;
                    494:        struct sshbuf *b = NULL;
                    495:
                    496:        *bp = NULL;
                    497:        memset(hash, 0, sizeof(hash));
1.1       djm       498:
1.2       djm       499:        if ((r = sshsig_check_hashalg(hashalg)) != 0)
                    500:                return r;
                    501:        if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
1.18      djm       502:                error_f("can't look up hash algorithm %s", hashalg);
1.2       djm       503:                return SSH_ERR_INTERNAL_ERROR;
                    504:        }
                    505:        if ((ctx = ssh_digest_start(alg)) == NULL) {
1.18      djm       506:                error_f("ssh_digest_start failed");
1.1       djm       507:                return SSH_ERR_INTERNAL_ERROR;
                    508:        }
                    509:        for (;;) {
                    510:                if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) {
                    511:                        if (errno == EINTR || errno == EAGAIN)
                    512:                                continue;
                    513:                        oerrno = errno;
1.18      djm       514:                        error_f("read: %s", strerror(errno));
1.1       djm       515:                        ssh_digest_free(ctx);
                    516:                        errno = oerrno;
1.2       djm       517:                        r = SSH_ERR_SYSTEM_ERROR;
                    518:                        goto out;
1.1       djm       519:                } else if (n == 0) {
1.18      djm       520:                        debug2_f("hashed %zu bytes", total);
1.1       djm       521:                        break; /* EOF */
                    522:                }
                    523:                total += (size_t)n;
                    524:                if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
1.18      djm       525:                        error_fr(r, "ssh_digest_update");
1.2       djm       526:                        goto out;
1.1       djm       527:                }
                    528:        }
1.2       djm       529:        if ((r = ssh_digest_final(ctx, hash, sizeof(hash))) != 0) {
1.18      djm       530:                error_fr(r, "ssh_digest_final");
1.2       djm       531:                goto out;
1.1       djm       532:        }
1.2       djm       533:        if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
1.18      djm       534:                debug3_f("final hash: %s", hex);
1.1       djm       535:                freezero(hex, strlen(hex));
                    536:        }
1.2       djm       537:        if ((b = sshbuf_new()) == NULL) {
                    538:                r = SSH_ERR_ALLOC_FAIL;
                    539:                goto out;
                    540:        }
                    541:        if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
1.18      djm       542:                error_fr(r, "sshbuf_put");
1.2       djm       543:                goto out;
                    544:        }
                    545:        *bp = b;
                    546:        b = NULL; /* transferred */
1.1       djm       547:        /* success */
1.2       djm       548:        r = 0;
                    549:  out:
                    550:        sshbuf_free(b);
1.1       djm       551:        ssh_digest_free(ctx);
1.2       djm       552:        explicit_bzero(hash, sizeof(hash));
1.12      markus    553:        return r;
1.1       djm       554: }
                    555:
                    556: int
1.16      djm       557: sshsig_sign_fd(struct sshkey *key, const char *hashalg,
                    558:     const char *sk_provider, const char *sk_pin,
1.1       djm       559:     int fd, const char *sig_namespace, struct sshbuf **out,
                    560:     sshsig_signer *signer, void *signer_ctx)
                    561: {
                    562:        struct sshbuf *b = NULL;
1.2       djm       563:        int r = SSH_ERR_INTERNAL_ERROR;
1.1       djm       564:
1.2       djm       565:        if (hashalg == NULL)
                    566:                hashalg = HASHALG_DEFAULT;
1.1       djm       567:        if (out != NULL)
                    568:                *out = NULL;
1.2       djm       569:        if ((r = hash_file(fd, hashalg, &b)) != 0) {
1.18      djm       570:                error_fr(r, "hash_file");
1.1       djm       571:                return r;
                    572:        }
1.16      djm       573:        if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
1.7       djm       574:            sig_namespace, out, signer, signer_ctx)) != 0)
1.1       djm       575:                goto out;
                    576:        /* success */
                    577:        r = 0;
                    578:  out:
                    579:        sshbuf_free(b);
                    580:        return r;
                    581: }
                    582:
                    583: int
                    584: sshsig_verify_fd(struct sshbuf *signature, int fd,
1.8       djm       585:     const char *expect_namespace, struct sshkey **sign_keyp,
                    586:     struct sshkey_sig_details **sig_details)
1.1       djm       587: {
                    588:        struct sshbuf *b = NULL;
1.2       djm       589:        int r = SSH_ERR_INTERNAL_ERROR;
1.1       djm       590:        char *hashalg = NULL;
                    591:
1.8       djm       592:        if (sig_details != NULL)
                    593:                *sig_details = NULL;
1.1       djm       594:        if (sign_keyp != NULL)
                    595:                *sign_keyp = NULL;
                    596:        if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
                    597:                return r;
1.18      djm       598:        debug_f("signature made with hash \"%s\"", hashalg);
1.2       djm       599:        if ((r = hash_file(fd, hashalg, &b)) != 0) {
1.18      djm       600:                error_fr(r, "hash_file");
1.1       djm       601:                goto out;
                    602:        }
                    603:        if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
1.8       djm       604:            sign_keyp, sig_details)) != 0)
1.1       djm       605:                goto out;
                    606:        /* success */
                    607:        r = 0;
                    608:  out:
                    609:        sshbuf_free(b);
                    610:        free(hashalg);
                    611:        return r;
                    612: }
                    613:
1.4       djm       614: struct sshsigopt {
1.1       djm       615:        int ca;
                    616:        char *namespaces;
1.21    ! djm       617:        uint64_t valid_after, valid_before;
1.1       djm       618: };
                    619:
1.4       djm       620: struct sshsigopt *
                    621: sshsigopt_parse(const char *opts, const char *path, u_long linenum,
1.1       djm       622:     const char **errstrp)
                    623: {
1.4       djm       624:        struct sshsigopt *ret;
1.1       djm       625:        int r;
1.21    ! djm       626:        char *opt;
1.1       djm       627:        const char *errstr = NULL;
                    628:
                    629:        if ((ret = calloc(1, sizeof(*ret))) == NULL)
                    630:                return NULL;
                    631:        if (opts == NULL || *opts == '\0')
                    632:                return ret; /* Empty options yields empty options :) */
                    633:
                    634:        while (*opts && *opts != ' ' && *opts != '\t') {
                    635:                /* flag options */
                    636:                if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
                    637:                        ret->ca = 1;
                    638:                } else if (opt_match(&opts, "namespaces")) {
                    639:                        if (ret->namespaces != NULL) {
                    640:                                errstr = "multiple \"namespaces\" clauses";
                    641:                                goto fail;
                    642:                        }
                    643:                        ret->namespaces = opt_dequote(&opts, &errstr);
                    644:                        if (ret->namespaces == NULL)
                    645:                                goto fail;
1.21    ! djm       646:                } else if (opt_match(&opts, "valid-after")) {
        !           647:                        if (ret->valid_after != 0) {
        !           648:                                errstr = "multiple \"valid-after\" clauses";
        !           649:                                goto fail;
        !           650:                        }
        !           651:                        if ((opt = opt_dequote(&opts, &errstr)) == NULL)
        !           652:                                goto fail;
        !           653:                        if (parse_absolute_time(opt, &ret->valid_after) != 0 ||
        !           654:                            ret->valid_after == 0) {
        !           655:                                free(opt);
        !           656:                                errstr = "invalid \"valid-after\" time";
        !           657:                                goto fail;
        !           658:                        }
        !           659:                        free(opt);
        !           660:                } else if (opt_match(&opts, "valid-before")) {
        !           661:                        if (ret->valid_before != 0) {
        !           662:                                errstr = "multiple \"valid-before\" clauses";
        !           663:                                goto fail;
        !           664:                        }
        !           665:                        if ((opt = opt_dequote(&opts, &errstr)) == NULL)
        !           666:                                goto fail;
        !           667:                        if (parse_absolute_time(opt, &ret->valid_before) != 0 ||
        !           668:                            ret->valid_before == 0) {
        !           669:                                free(opt);
        !           670:                                errstr = "invalid \"valid-before\" time";
        !           671:                                goto fail;
        !           672:                        }
        !           673:                        free(opt);
1.1       djm       674:                }
                    675:                /*
                    676:                 * Skip the comma, and move to the next option
                    677:                 * (or break out if there are no more).
                    678:                 */
                    679:                if (*opts == '\0' || *opts == ' ' || *opts == '\t')
                    680:                        break;          /* End of options. */
                    681:                /* Anything other than a comma is an unknown option */
                    682:                if (*opts != ',') {
                    683:                        errstr = "unknown key option";
                    684:                        goto fail;
                    685:                }
                    686:                opts++;
                    687:                if (*opts == '\0') {
                    688:                        errstr = "unexpected end-of-options";
                    689:                        goto fail;
                    690:                }
                    691:        }
1.21    ! djm       692:        /* final consistency check */
        !           693:        if (ret->valid_after != 0 && ret->valid_before != 0 &&
        !           694:            ret->valid_before <= ret->valid_after) {
        !           695:                errstr = "\"valid-before\" time is before \"valid-after\"";
        !           696:                goto fail;
        !           697:        }
1.1       djm       698:        /* success */
                    699:        return ret;
                    700:  fail:
                    701:        if (errstrp != NULL)
                    702:                *errstrp = errstr;
1.5       djm       703:        sshsigopt_free(ret);
1.1       djm       704:        return NULL;
                    705: }
                    706:
1.4       djm       707: void
                    708: sshsigopt_free(struct sshsigopt *opts)
1.1       djm       709: {
                    710:        if (opts == NULL)
                    711:                return;
                    712:        free(opts->namespaces);
                    713:        free(opts);
                    714: }
                    715:
                    716: static int
1.9       djm       717: parse_principals_key_and_options(const char *path, u_long linenum, char *line,
                    718:     const char *required_principal, char **principalsp, struct sshkey **keyp,
                    719:     struct sshsigopt **sigoptsp)
1.1       djm       720: {
1.9       djm       721:        char *opts = NULL, *tmp, *cp, *principals = NULL;
1.1       djm       722:        const char *reason = NULL;
1.4       djm       723:        struct sshsigopt *sigopts = NULL;
1.9       djm       724:        struct sshkey *key = NULL;
                    725:        int r = SSH_ERR_INTERNAL_ERROR;
1.1       djm       726:
1.9       djm       727:        if (principalsp != NULL)
                    728:                *principalsp = NULL;
                    729:        if (sigoptsp != NULL)
                    730:                *sigoptsp = NULL;
                    731:        if (keyp != NULL)
                    732:                *keyp = NULL;
1.1       djm       733:
                    734:        cp = line;
                    735:        cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
                    736:        if (*cp == '#' || *cp == '\0')
1.9       djm       737:                return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
                    738:
                    739:        /* format: identity[,identity...] [option[,option...]] key */
                    740:        if ((tmp = strdelimw(&cp)) == NULL) {
1.1       djm       741:                error("%s:%lu: invalid line", path, linenum);
1.9       djm       742:                r = SSH_ERR_INVALID_FORMAT;
                    743:                goto out;
1.1       djm       744:        }
1.9       djm       745:        if ((principals = strdup(tmp)) == NULL) {
1.18      djm       746:                error_f("strdup failed");
1.9       djm       747:                r = SSH_ERR_ALLOC_FAIL;
                    748:                goto out;
                    749:        }
                    750:        /*
                    751:         * Bail out early if we're looking for a particular principal and this
                    752:         * line does not list it.
                    753:         */
                    754:        if (required_principal != NULL) {
                    755:                if (match_pattern_list(required_principal,
                    756:                    principals, 0) != 1) {
                    757:                        /* principal didn't match */
                    758:                        r = SSH_ERR_KEY_NOT_FOUND;
                    759:                        goto out;
                    760:                }
1.18      djm       761:                debug_f("%s:%lu: matched principal \"%s\"",
                    762:                    path, linenum, required_principal);
1.1       djm       763:        }
                    764:
1.9       djm       765:        if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
1.18      djm       766:                error_f("sshkey_new failed");
1.9       djm       767:                r = SSH_ERR_ALLOC_FAIL;
                    768:                goto out;
                    769:        }
                    770:        if (sshkey_read(key, &cp) != 0) {
1.1       djm       771:                /* no key? Check for options */
                    772:                opts = cp;
                    773:                if (sshkey_advance_past_options(&cp) != 0) {
1.9       djm       774:                        error("%s:%lu: invalid options", path, linenum);
                    775:                        r = SSH_ERR_INVALID_FORMAT;
                    776:                        goto out;
1.1       djm       777:                }
                    778:                *cp++ = '\0';
                    779:                skip_space(&cp);
1.9       djm       780:                if (sshkey_read(key, &cp) != 0) {
                    781:                        error("%s:%lu: invalid key", path, linenum);
                    782:                        r = SSH_ERR_INVALID_FORMAT;
                    783:                        goto out;
1.1       djm       784:                }
                    785:        }
                    786:        debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
1.4       djm       787:        if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
1.1       djm       788:                error("%s:%lu: bad options: %s", path, linenum, reason);
1.9       djm       789:                r = SSH_ERR_INVALID_FORMAT;
                    790:                goto out;
                    791:        }
                    792:        /* success */
                    793:        if (principalsp != NULL) {
                    794:                *principalsp = principals;
                    795:                principals = NULL; /* transferred */
                    796:        }
                    797:        if (sigoptsp != NULL) {
                    798:                *sigoptsp = sigopts;
                    799:                sigopts = NULL; /* transferred */
                    800:        }
                    801:        if (keyp != NULL) {
                    802:                *keyp = key;
                    803:                key = NULL; /* transferred */
                    804:        }
                    805:        r = 0;
                    806:  out:
                    807:        free(principals);
                    808:        sshsigopt_free(sigopts);
                    809:        sshkey_free(key);
                    810:        return r;
                    811: }
                    812:
                    813: static int
                    814: check_allowed_keys_line(const char *path, u_long linenum, char *line,
                    815:     const struct sshkey *sign_key, const char *principal,
1.21    ! djm       816:     const char *sig_namespace, uint64_t verify_time)
1.9       djm       817: {
                    818:        struct sshkey *found_key = NULL;
1.21    ! djm       819:        int r, success = 0;
1.9       djm       820:        const char *reason = NULL;
                    821:        struct sshsigopt *sigopts = NULL;
1.21    ! djm       822:        char tvalid[64], tverify[64];
1.9       djm       823:
                    824:        /* Parse the line */
                    825:        if ((r = parse_principals_key_and_options(path, linenum, line,
                    826:            principal, NULL, &found_key, &sigopts)) != 0) {
                    827:                /* error already logged */
1.1       djm       828:                goto done;
                    829:        }
                    830:
                    831:        if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
                    832:                /* Exact match of key */
1.21    ! djm       833:                debug("%s:%lu: matched key", path, linenum);
1.1       djm       834:        } else if (sigopts->ca && sshkey_is_cert(sign_key) &&
                    835:            sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
                    836:                /* Match of certificate's CA key */
1.19      djm       837:                if ((r = sshkey_cert_check_authority(sign_key, 0, 1, 0,
1.21    ! djm       838:                    verify_time, principal, &reason)) != 0) {
1.1       djm       839:                        error("%s:%lu: certificate not authorized: %s",
                    840:                            path, linenum, reason);
                    841:                        goto done;
                    842:                }
                    843:                debug("%s:%lu: matched certificate CA key", path, linenum);
                    844:        } else {
1.21    ! djm       845:                /* Didn't match key */
1.1       djm       846:                goto done;
                    847:        }
1.21    ! djm       848:
        !           849:        /* Check whether options preclude the use of this key */
        !           850:        if (sigopts->namespaces != NULL &&
        !           851:            match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) {
        !           852:                error("%s:%lu: key is not permitted for use in signature "
        !           853:                    "namespace \"%s\"", path, linenum, sig_namespace);
        !           854:                goto done;
        !           855:        }
        !           856:
        !           857:        /* check key time validity */
        !           858:        format_absolute_time((uint64_t)verify_time, tverify, sizeof(tverify));
        !           859:        if (sigopts->valid_after != 0 &&
        !           860:            (uint64_t)verify_time < sigopts->valid_after) {
        !           861:                format_absolute_time(sigopts->valid_after,
        !           862:                    tvalid, sizeof(tvalid));
        !           863:                error("%s:%lu: key is not yet valid: "
        !           864:                    "verify time %s < valid-after %s", path, linenum,
        !           865:                    tverify, tvalid);
        !           866:                goto done;
        !           867:        }
        !           868:        if (sigopts->valid_before != 0 &&
        !           869:            (uint64_t)verify_time > sigopts->valid_before) {
        !           870:                format_absolute_time(sigopts->valid_before,
        !           871:                    tvalid, sizeof(tvalid));
        !           872:                error("%s:%lu: key has expired: "
        !           873:                    "verify time %s > valid-before %s", path, linenum,
        !           874:                    tverify, tvalid);
        !           875:                goto done;
        !           876:        }
        !           877:        success = 1;
        !           878:
1.1       djm       879:  done:
                    880:        sshkey_free(found_key);
1.4       djm       881:        sshsigopt_free(sigopts);
1.21    ! djm       882:        return success ? 0 : SSH_ERR_KEY_NOT_FOUND;
1.1       djm       883: }
                    884:
                    885: int
                    886: sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
1.21    ! djm       887:     const char *principal, const char *sig_namespace, uint64_t verify_time)
1.1       djm       888: {
                    889:        FILE *f = NULL;
                    890:        char *line = NULL;
                    891:        size_t linesize = 0;
                    892:        u_long linenum = 0;
1.12      markus    893:        int r = SSH_ERR_INTERNAL_ERROR, oerrno;
1.1       djm       894:
                    895:        /* Check key and principal against file */
                    896:        if ((f = fopen(path, "r")) == NULL) {
                    897:                oerrno = errno;
                    898:                error("Unable to open allowed keys file \"%s\": %s",
                    899:                    path, strerror(errno));
                    900:                errno = oerrno;
                    901:                return SSH_ERR_SYSTEM_ERROR;
                    902:        }
                    903:
                    904:        while (getline(&line, &linesize, f) != -1) {
                    905:                linenum++;
                    906:                r = check_allowed_keys_line(path, linenum, line, sign_key,
1.21    ! djm       907:                    principal, sig_namespace, verify_time);
1.2       djm       908:                free(line);
                    909:                line = NULL;
1.20      dtucker   910:                linesize = 0;
1.1       djm       911:                if (r == SSH_ERR_KEY_NOT_FOUND)
                    912:                        continue;
                    913:                else if (r == 0) {
                    914:                        /* success */
                    915:                        fclose(f);
                    916:                        return 0;
                    917:                } else
                    918:                        break;
                    919:        }
                    920:        /* Either we hit an error parsing or we simply didn't find the key */
                    921:        fclose(f);
                    922:        free(line);
                    923:        return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
                    924: }
1.10      djm       925:
                    926: static int
1.11      djm       927: cert_filter_principals(const char *path, u_long linenum,
1.21    ! djm       928:     char **principalsp, const struct sshkey *cert, uint64_t verify_time)
1.11      djm       929: {
                    930:        char *cp, *oprincipals, *principals;
                    931:        const char *reason;
                    932:        struct sshbuf *nprincipals;
                    933:        int r = SSH_ERR_INTERNAL_ERROR, success = 0;
                    934:
                    935:        oprincipals = principals = *principalsp;
                    936:        *principalsp = NULL;
                    937:
1.15      markus    938:        if ((nprincipals = sshbuf_new()) == NULL) {
                    939:                r = SSH_ERR_ALLOC_FAIL;
                    940:                goto out;
                    941:        }
1.11      djm       942:
                    943:        while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
                    944:                if (strcspn(cp, "!?*") != strlen(cp)) {
                    945:                        debug("%s:%lu: principal \"%s\" not authorized: "
                    946:                            "contains wildcards", path, linenum, cp);
                    947:                        continue;
                    948:                }
                    949:                /* Check against principals list in certificate */
1.19      djm       950:                if ((r = sshkey_cert_check_authority(cert, 0, 1, 0,
1.21    ! djm       951:                    verify_time, cp, &reason)) != 0) {
1.11      djm       952:                        debug("%s:%lu: principal \"%s\" not authorized: %s",
                    953:                            path, linenum, cp, reason);
                    954:                        continue;
                    955:                }
                    956:                if ((r = sshbuf_putf(nprincipals, "%s%s",
                    957:                    sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) {
1.18      djm       958:                        error_f("buffer error");
1.11      djm       959:                        goto out;
                    960:                }
                    961:        }
                    962:        if (sshbuf_len(nprincipals) == 0) {
                    963:                error("%s:%lu: no valid principals found", path, linenum);
                    964:                r = SSH_ERR_KEY_CERT_INVALID;
                    965:                goto out;
                    966:        }
                    967:        if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
1.18      djm       968:                error_f("buffer error");
1.11      djm       969:                goto out;
                    970:        }
                    971:        /* success */
                    972:        success = 1;
                    973:        *principalsp = principals;
                    974:  out:
                    975:        sshbuf_free(nprincipals);
                    976:        free(oprincipals);
                    977:        return success ? 0 : r;
                    978: }
                    979:
                    980: static int
                    981: get_matching_principals_from_line(const char *path, u_long linenum, char *line,
1.21    ! djm       982:     const struct sshkey *sign_key, uint64_t verify_time, char **principalsp)
1.10      djm       983: {
                    984:        struct sshkey *found_key = NULL;
                    985:        char *principals = NULL;
                    986:        int r, found = 0;
                    987:        struct sshsigopt *sigopts = NULL;
                    988:
                    989:        if (principalsp != NULL)
                    990:                *principalsp = NULL;
                    991:
                    992:        /* Parse the line */
                    993:        if ((r = parse_principals_key_and_options(path, linenum, line,
                    994:            NULL, &principals, &found_key, &sigopts)) != 0) {
                    995:                /* error already logged */
                    996:                goto done;
                    997:        }
                    998:
                    999:        if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
                   1000:                /* Exact match of key */
                   1001:                debug("%s:%lu: matched key", path, linenum);
                   1002:                /* success */
                   1003:                found = 1;
                   1004:        } else if (sigopts->ca && sshkey_is_cert(sign_key) &&
                   1005:            sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
1.11      djm      1006:                /* Remove principals listed in file but not allowed by cert */
                   1007:                if ((r = cert_filter_principals(path, linenum,
1.21    ! djm      1008:                    &principals, sign_key, verify_time)) != 0) {
1.11      djm      1009:                        /* error already displayed */
1.18      djm      1010:                        debug_r(r, "%s:%lu: cert_filter_principals",
                   1011:                            path, linenum);
1.10      djm      1012:                        goto done;
                   1013:                }
                   1014:                debug("%s:%lu: matched certificate CA key", path, linenum);
                   1015:                /* success */
                   1016:                found = 1;
                   1017:        } else {
                   1018:                /* Key didn't match */
                   1019:                goto done;
                   1020:        }
                   1021:  done:
1.13      markus   1022:        if (found && principalsp != NULL) {
1.10      djm      1023:                *principalsp = principals;
                   1024:                principals = NULL; /* transferred */
                   1025:        }
                   1026:        free(principals);
                   1027:        sshkey_free(found_key);
                   1028:        sshsigopt_free(sigopts);
                   1029:        return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
                   1030: }
                   1031:
                   1032: int
1.11      djm      1033: sshsig_find_principals(const char *path, const struct sshkey *sign_key,
1.21    ! djm      1034:     uint64_t verify_time, char **principals)
1.10      djm      1035: {
                   1036:        FILE *f = NULL;
                   1037:        char *line = NULL;
                   1038:        size_t linesize = 0;
                   1039:        u_long linenum = 0;
1.14      markus   1040:        int r = SSH_ERR_INTERNAL_ERROR, oerrno;
1.10      djm      1041:
                   1042:        if ((f = fopen(path, "r")) == NULL) {
                   1043:                oerrno = errno;
                   1044:                error("Unable to open allowed keys file \"%s\": %s",
                   1045:                    path, strerror(errno));
                   1046:                errno = oerrno;
                   1047:                return SSH_ERR_SYSTEM_ERROR;
                   1048:        }
                   1049:
                   1050:        while (getline(&line, &linesize, f) != -1) {
                   1051:                linenum++;
1.11      djm      1052:                r = get_matching_principals_from_line(path, linenum, line,
1.21    ! djm      1053:                    sign_key, verify_time, principals);
1.10      djm      1054:                free(line);
                   1055:                line = NULL;
1.20      dtucker  1056:                linesize = 0;
1.10      djm      1057:                if (r == SSH_ERR_KEY_NOT_FOUND)
                   1058:                        continue;
                   1059:                else if (r == 0) {
                   1060:                        /* success */
                   1061:                        fclose(f);
                   1062:                        return 0;
                   1063:                } else
                   1064:                        break;
                   1065:        }
                   1066:        free(line);
                   1067:        /* Either we hit an error parsing or we simply didn't find the key */
                   1068:        if (ferror(f) != 0) {
                   1069:                oerrno = errno;
                   1070:                fclose(f);
                   1071:                error("Unable to read allowed keys file \"%s\": %s",
                   1072:                    path, strerror(errno));
                   1073:                errno = oerrno;
                   1074:                return SSH_ERR_SYSTEM_ERROR;
                   1075:        }
                   1076:        fclose(f);
                   1077:        return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
                   1078: }
                   1079:
                   1080: int
                   1081: sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
                   1082: {
                   1083:        struct sshkey *pk = NULL;
                   1084:        int r = SSH_ERR_SIGNATURE_INVALID;
                   1085:
1.13      markus   1086:        if (pubkey == NULL)
                   1087:                return SSH_ERR_INTERNAL_ERROR;
1.10      djm      1088:        if ((r = sshsig_parse_preamble(signature)) != 0)
                   1089:                return r;
                   1090:        if ((r = sshkey_froms(signature, &pk)) != 0)
                   1091:                return r;
                   1092:
                   1093:        *pubkey = pk;
                   1094:        pk = NULL;
                   1095:        return 0;
                   1096: }