=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshsig.c,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- src/usr.bin/ssh/sshsig.c 2020/01/22 02:25:21 1.9 +++ src/usr.bin/ssh/sshsig.c 2020/01/23 02:43:48 1.10 @@ -864,3 +864,120 @@ free(line); return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; } + +static int +get_matching_principal_from_line(const char *path, u_long linenum, char *line, + const struct sshkey *sign_key, char **principalsp) +{ + struct sshkey *found_key = NULL; + char *principals = NULL; + int r, found = 0; + const char *reason = NULL; + struct sshsigopt *sigopts = NULL; + + if (principalsp != NULL) + *principalsp = NULL; + + /* Parse the line */ + if ((r = parse_principals_key_and_options(path, linenum, line, + NULL, &principals, &found_key, &sigopts)) != 0) { + /* error already logged */ + goto done; + } + + if (!sigopts->ca && sshkey_equal(found_key, sign_key)) { + /* Exact match of key */ + debug("%s:%lu: matched key", path, linenum); + /* success */ + found = 1; + } else if (sigopts->ca && sshkey_is_cert(sign_key) && + sshkey_equal_public(sign_key->cert->signature_key, found_key)) { + /* Match of certificate's CA key */ + if ((r = sshkey_cert_check_authority(sign_key, 0, 1, + principals, &reason)) != 0) { + error("%s:%lu: certificate not authorized: %s", + path, linenum, reason); + goto done; + } + debug("%s:%lu: matched certificate CA key", path, linenum); + /* success */ + found = 1; + } else { + /* Key didn't match */ + goto done; + } + done: + if (found) { + *principalsp = principals; + principals = NULL; /* transferred */ + } + free(principals); + sshkey_free(found_key); + sshsigopt_free(sigopts); + return found ? 0 : SSH_ERR_KEY_NOT_FOUND; +} + +int +sshsig_find_principal(const char *path, const struct sshkey *sign_key, + char **principal) +{ + FILE *f = NULL; + char *line = NULL; + size_t linesize = 0; + u_long linenum = 0; + int r, oerrno; + + if ((f = fopen(path, "r")) == NULL) { + oerrno = errno; + error("Unable to open allowed keys file \"%s\": %s", + path, strerror(errno)); + errno = oerrno; + return SSH_ERR_SYSTEM_ERROR; + } + + while (getline(&line, &linesize, f) != -1) { + linenum++; + r = get_matching_principal_from_line(path, linenum, line, + sign_key, principal); + free(line); + line = NULL; + if (r == SSH_ERR_KEY_NOT_FOUND) + continue; + else if (r == 0) { + /* success */ + fclose(f); + return 0; + } else + break; + } + free(line); + /* Either we hit an error parsing or we simply didn't find the key */ + if (ferror(f) != 0) { + oerrno = errno; + fclose(f); + error("Unable to read allowed keys file \"%s\": %s", + path, strerror(errno)); + errno = oerrno; + return SSH_ERR_SYSTEM_ERROR; + } + fclose(f); + return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; +} + +int +sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey) +{ + struct sshkey *pk = NULL; + int r = SSH_ERR_SIGNATURE_INVALID; + + if (pubkey != NULL) + *pubkey = NULL; + if ((r = sshsig_parse_preamble(signature)) != 0) + return r; + if ((r = sshkey_froms(signature, &pk)) != 0) + return r; + + *pubkey = pk; + pk = NULL; + return 0; +}