Download raw body.
Tag signing with SSH signatures
On Thu, Jun 30, 2022 at 07:37:22AM -0400, Josh Rickmar wrote: > Here's a first try at creating and verifying tags signed by SSH > signatures. I've yet to write the documentation or regress tests but > eager others can begin to look over the implementation. Feedback > welcome :) > > A new -s flag is added to got tag when creating signatures which > specifies which key to use to sign with. For example: > > $ got tag -s /home/jrick/.ssh/id_ed25519 tag_name > > The SSH signature appears at the end of the tag message. This is what > git also does when signing with SSH keys. Right now we are not > clipping this signature from any displayed tag messages, but that can > be done. > > Verification is done with a new -V flag introduced to got tag. It > also requires creating an allowed signers file (see ssh-keygen(1)) and > providing the path in your got.conf(5) with a new allowed_signers > directive. > > $ cat .got/got.conf > allowed_signers "/home/jrick/allowed_signers" > $ cat /home/jrick/allowed_signers > jrick@zettaport.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMfooXuB1k6zimkfBzbMTTuRupF3u+56Pun4pJmEQuTI > $ got tag -V sig_test > ----------------------------------------------- > tag sig_test d2de9fffa937cbff70ffe59494acdecda86224b6 > from: Josh Rickmar <jrick@zettaport.com> > date: Thu Jun 30 11:20:00 2022 UTC > object: commit 9b058f456d15d60a89334ce3e7f0a7c22e182c55 > signature: Good "git" signature for jrick@zettaport.com with ED25519 key SHA256:LCWFweH6pA7DYiP/WMDYthnbM3HiOJBxG0/29179Fkg > > hi > -----BEGIN SSH SIGNATURE----- > U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgx+ihe4HWTrOKaR8HNsxNO5G6kX > e77no+6fikmYRC5MgAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 > AAAAQOkShDme1WiGDAz+DAIpcjEZSIblFFeOJsTpoJPYo409kJGmTuxh9vfth0MrrtyZ0k > eEY9I0BIfQ+czIriAnaAs= > -----END SSH SIGNATURE----- > See below. And you forgot to fix gotweb. > diff refs/heads/main refs/heads/ssh_sigs > commit - 9b058f456d15d60a89334ce3e7f0a7c22e182c55 > commit + cebbdb6cf3dcd1c91cd6551c00afa271ea77c2e2 > blob - 8dfd844f3da472b6ed040a62acaf85403cbc07ea > blob + 21f8d657a812ed856524bf6db776b0534b6939b4 > --- got/Makefile > +++ got/Makefile > @@ -13,7 +13,7 @@ SRCS= got.c blame.c commit_graph.c delta.c diff.c \ > diff_myers.c diff_output.c diff_output_plain.c \ > diff_output_unidiff.c diff_output_edscript.c \ > diff_patience.c send.c deltify.c pack_create.c dial.c \ > - bloom.c murmurhash2.c ratelimit.c patch.c > + bloom.c murmurhash2.c ratelimit.c patch.c tag.c date.c > > MAN = ${PROG}.1 got-worktree.5 git-repository.5 got.conf.5 > > blob - 2dceeed3a7a54bee61a491f92527df8295059f95 > blob + 422dbc8d83e81efe3f1f4faef1c59cc7f9ac72db > --- got/got.c > +++ got/got.c > @@ -58,6 +58,8 @@ > #include "got_gotconfig.h" > #include "got_dial.h" > #include "got_patch.h" > +#include "got_tag.h" > +#include "got_date.h" > > #ifndef nitems > #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) > @@ -687,6 +689,76 @@ get_author(char **author, struct got_repository *repo, > } > > static const struct got_error * > +get_allowed_signers(char **allowed_signers, struct got_repository *repo, > + struct got_worktree *worktree) > +{ > + const char *got_allowed_signers = NULL; > + const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; > + > + *allowed_signers = NULL; > + > + if (worktree) > + worktree_conf = got_worktree_get_gotconfig(worktree); > + repo_conf = got_repo_get_gotconfig(repo); > + > + /* > + * Priority of potential author information sources, from most > + * significant to least significant: > + * 1) work tree's .got/got.conf file > + * 2) repository's got.conf file > + */ > + > + if (worktree_conf) > + got_allowed_signers = got_gotconfig_get_allowed_signers_file( > + worktree_conf); > + if (got_allowed_signers == NULL) > + got_allowed_signers = got_gotconfig_get_allowed_signers_file( > + repo_conf); > + > + if (got_allowed_signers) { > + *allowed_signers = strdup(got_allowed_signers); > + if (*allowed_signers == NULL) > + return got_error_from_errno("strdup"); > + } > + return NULL; > +} > + > +static const struct got_error * > +get_revoked_signers(char **revoked_signers, struct got_repository *repo, > + struct got_worktree *worktree) > +{ > + const char *got_revoked_signers = NULL; > + const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; > + > + *revoked_signers = NULL; > + > + if (worktree) > + worktree_conf = got_worktree_get_gotconfig(worktree); > + repo_conf = got_repo_get_gotconfig(repo); > + > + /* > + * Priority of potential author information sources, from most > + * significant to least significant: > + * 1) work tree's .got/got.conf file > + * 2) repository's got.conf file > + */ > + > + if (worktree_conf) > + got_revoked_signers = got_gotconfig_get_revoked_signers_file( > + worktree_conf); > + if (got_revoked_signers == NULL) > + got_revoked_signers = got_gotconfig_get_revoked_signers_file( > + repo_conf); > + > + if (got_revoked_signers) { > + *revoked_signers = strdup(got_revoked_signers); > + if (*revoked_signers == NULL) > + return got_error_from_errno("strdup"); > + } > + return NULL; > +} > + > +static const struct got_error * > get_gitconfig_path(char **gitconfig_path) > { > const char *homedir = getenv("HOME"); > @@ -6807,7 +6879,8 @@ usage_tag(void) > { > fprintf(stderr, > "usage: %s tag [-c commit] [-r repository] [-l] " > - "[-m message] name\n", getprogname()); > + "[-m message] [-s signer_id] name\n", > + getprogname()); > exit(1); > } > > @@ -6887,7 +6960,8 @@ get_tag_refname(char **refname, const char *tag_name) > } > > static const struct got_error * > -list_tags(struct got_repository *repo, const char *tag_name) > +list_tags(struct got_repository *repo, const char *tag_name, int verify_tags, > + const char *allowed_signers, const char *revoked_signers, int verbosity) > { > static const struct got_error *err = NULL; > struct got_reflist_head refs; > @@ -6916,7 +6990,8 @@ list_tags(struct got_repository *repo, const char *tag > const char *refname; > char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr; > char datebuf[26]; > - const char *tagger; > + const char *tagger, *ssh_sig = NULL; > + char *sig_msg = NULL; > time_t tagger_time; > struct got_object_id *id; > struct got_tag_object *tag; > @@ -6932,8 +7007,6 @@ list_tags(struct got_repository *repo, const char *tag > err = got_error_from_errno("got_ref_to_str"); > break; > } > - printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); > - free(refstr); > > err = got_ref_resolve(&id, repo, re->ref); > if (err) > @@ -6966,6 +7039,22 @@ list_tags(struct got_repository *repo, const char *tag > if (err) > break; > } > + > + if (verify_tags) { > + ssh_sig = got_tag_message_get_ssh_signature( > + got_object_tag_get_message(tag)); > + if (ssh_sig && allowed_signers == NULL) { > + err = got_error_msg( > + GOT_ERR_CANTVERIFY_TAG_SIGNATURE, > + "SSH signature verification requires " > + "setting allowed_signers in " > + "got.conf(5)"); > + break; > + } > + } > + > + printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); > + free(refstr); > printf("from: %s\n", tagger); > datestr = get_datestr(&tagger_time, datebuf); > if (datestr) > @@ -6995,6 +7084,17 @@ list_tags(struct got_repository *repo, const char *tag > } > } > free(id_str); > + > + if (ssh_sig) { > + err = got_tag_verify_ssh(&sig_msg, tag, ssh_sig, > + allowed_signers, revoked_signers, 0); > + if (err) > + break; > + printf("signature: %s", sig_msg); > + free(sig_msg); > + sig_msg = NULL; > + } > + > if (commit) { > err = got_object_commit_get_logmsg(&tagmsg0, commit); > if (err) > @@ -7068,9 +7168,6 @@ done: > if (fd != -1 && close(fd) == -1 && err == NULL) > err = got_error_from_errno2("close", *tagmsg_path); > > - /* Editor is done; we can now apply unveil(2) */ > - if (err == NULL) > - err = apply_unveil(repo_path, 0, NULL); > if (err) { > free(*tagmsg); > *tagmsg = NULL; > @@ -7080,7 +7177,8 @@ done: > > static const struct got_error * > add_tag(struct got_repository *repo, const char *tagger, > - const char *tag_name, const char *commit_arg, const char *tagmsg_arg) > + const char *tag_name, const char *commit_arg, const char *tagmsg_arg, > + const char *key_file, int verbosity) > { > const struct got_error *err = NULL; > struct got_object_id *commit_id = NULL, *tag_id = NULL; > @@ -7136,10 +7234,18 @@ add_tag(struct got_repository *repo, const char *tagge > preserve_tagmsg = 1; > goto done; > } > + /* Editor is done; we can now apply unveil(2) */ > + err = got_tag_apply_unveil(); > + if (err) > + goto done; > + err = apply_unveil(got_repo_get_path(repo), 0, NULL); > + if (err) > + goto done; > } > > err = got_object_tag_create(&tag_id, tag_name, commit_id, > - tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, repo); > + tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, key_file, repo, > + verbosity); > if (err) { > if (tagmsg_path) > preserve_tagmsg = 1; > @@ -7193,11 +7299,13 @@ cmd_tag(int argc, char *argv[]) > struct got_worktree *worktree = NULL; > char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL; > char *gitconfig_path = NULL, *tagger = NULL; > + char *allowed_signers = NULL, *revoked_signers = NULL; > const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL; > - int ch, do_list = 0; > + int ch, do_list = 0, verify_tags = 0, verbosity = 0; > + const char *signer_id = NULL; > int *pack_fds = NULL; > > - while ((ch = getopt(argc, argv, "c:m:r:l")) != -1) { > + while ((ch = getopt(argc, argv, "c:m:r:ls:Vv")) != -1) { > switch (ch) { > case 'c': > commit_id_arg = optarg; > @@ -7215,6 +7323,18 @@ cmd_tag(int argc, char *argv[]) > case 'l': > do_list = 1; > break; > + case 's': > + signer_id = optarg; > + break; > + case 'V': > + verify_tags = 1; > + break; > + case 'v': > + if (verbosity < 0) > + verbosity = 0; > + else if (verbosity < 3) > + verbosity++; > + break; > default: > usage_tag(); > /* NOTREACHED */ > @@ -7275,26 +7395,40 @@ cmd_tag(int argc, char *argv[]) > } > } > > - if (do_list) { > + if (do_list || verify_tags) { > + error = got_repo_open(&repo, repo_path, NULL, pack_fds); > + if (error != NULL) > + goto done; > + error = get_allowed_signers(&allowed_signers, repo, worktree); > + if (error) > + goto done; > + error = get_revoked_signers(&revoked_signers, repo, worktree); > + if (error) > + goto done; > if (worktree) { > /* Release work tree lock. */ > got_worktree_close(worktree); > worktree = NULL; > } > - error = got_repo_open(&repo, repo_path, NULL, pack_fds); > - if (error != NULL) > - goto done; > > + /* > + * Remove "cpath" promise unless needed for signature tmpfile > + * creation. > + */ > + if (verify_tags) > + got_tag_apply_unveil(); > + else { > #ifndef PROFILE > - /* Remove "cpath" promise. */ > - if (pledge("stdio rpath wpath flock proc exec sendfd unveil", > - NULL) == -1) > - err(1, "pledge"); > + if (pledge("stdio rpath wpath flock proc exec sendfd " > + "unveil", NULL) == -1) > + err(1, "pledge"); > #endif > + } > error = apply_unveil(got_repo_get_path(repo), 1, NULL); > if (error) > goto done; > - error = list_tags(repo, tag_name); > + error = list_tags(repo, tag_name, verify_tags, allowed_signers, > + revoked_signers, verbosity); > } else { > error = get_gitconfig_path(&gitconfig_path); > if (error) > @@ -7314,6 +7448,11 @@ cmd_tag(int argc, char *argv[]) > } > > if (tagmsg) { > + if (signer_id) { > + error = got_tag_apply_unveil(); > + if (error) > + goto done; > + } > error = apply_unveil(got_repo_get_path(repo), 0, NULL); > if (error) > goto done; > @@ -7338,7 +7477,8 @@ cmd_tag(int argc, char *argv[]) > } > > error = add_tag(repo, tagger, tag_name, > - commit_id_str ? commit_id_str : commit_id_arg, tagmsg); > + commit_id_str ? commit_id_str : commit_id_arg, tagmsg, > + signer_id, verbosity); > } > done: > if (repo) { > @@ -7359,6 +7499,8 @@ done: > free(gitconfig_path); > free(commit_id_str); > free(tagger); > + free(allowed_signers); > + free(revoked_signers); > return error; > } > > @@ -12388,22 +12530,6 @@ cat_tree(struct got_object_id *id, struct got_reposito > return err; > } > > -static void > -format_gmtoff(char *buf, size_t sz, time_t gmtoff) > -{ > - long long h, m; > - char sign = '+'; > - > - if (gmtoff < 0) { > - sign = '-'; > - gmtoff = -gmtoff; > - } > - > - h = (long long)gmtoff / 3600; > - m = ((long long)gmtoff - h*3600) / 60; > - snprintf(buf, sz, "%c%02lld%02lld", sign, h, m); > -} > - > static const struct got_error * > cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile) > { > @@ -12435,14 +12561,14 @@ cat_commit(struct got_object_id *id, struct got_reposi > fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str); > free(pid_str); > } > - format_gmtoff(gmtoff, sizeof(gmtoff), > + got_format_gmtoff(gmtoff, sizeof(gmtoff), > got_object_commit_get_author_gmtoff(commit)); > fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR, > got_object_commit_get_author(commit), > (long long)got_object_commit_get_author_time(commit), > gmtoff); > > - format_gmtoff(gmtoff, sizeof(gmtoff), > + got_format_gmtoff(gmtoff, sizeof(gmtoff), > got_object_commit_get_committer_gmtoff(commit)); > fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER, > got_object_commit_get_author(commit), > @@ -12501,7 +12627,7 @@ cat_tag(struct got_object_id *id, struct got_repositor > fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG, > got_object_tag_get_name(tag)); > > - format_gmtoff(gmtoff, sizeof(gmtoff), > + got_format_gmtoff(gmtoff, sizeof(gmtoff), > got_object_tag_get_tagger_gmtoff(tag)); > fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER, > got_object_tag_get_tagger(tag), > blob - 781133bbc9837ad999231c521ae9da3239c0232b > blob + f9ea174585d6eddc3416290cb385a2b4c190ac41 > --- gotadmin/Makefile > +++ gotadmin/Makefile > @@ -8,7 +8,8 @@ SRCS= gotadmin.c \ > inflate.c lockfile.c object.c object_cache.c object_create.c \ > object_idset.c object_parse.c opentemp.c pack.c pack_create.c \ > path.c privsep.c reference.c repository.c repository_admin.c \ > - worktree_open.c sha1.c bloom.c murmurhash2.c ratelimit.c > + worktree_open.c sha1.c bloom.c murmurhash2.c ratelimit.c tag.c \ > + buf.c date.c > MAN = ${PROG}.1 > > CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib > blob - /dev/null > blob + b377deed4284643517139184442dbef62e88b453 (mode 644) > --- /dev/null > +++ include/got_date.h > @@ -0,0 +1,18 @@ > +/* > + * Copyright (c) 2022 Josh Rickmar <jrick@zettaport.com> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +void > +got_format_gmtoff(char *, size_t, time_t); > blob - 22a9264b9f8d0c0b20b48895dd8ea59708e61d48 > blob + 818d096c51e0f1978febbe41ed56f812cc1f33e6 > --- include/got_error.h > +++ include/got_error.h > @@ -169,6 +169,8 @@ > #define GOT_ERR_PATCH_FAILED 151 > #define GOT_ERR_FILEIDX_DUP_ENTRY 152 > #define GOT_ERR_PIN_PACK 153 > +#define GOT_ERR_BAD_TAG_SIGNATURE 154 > +#define GOT_ERR_CANTVERIFY_TAG_SIGNATURE 155 > > struct got_error { > int code; > blob - 3dbe5d7d43cf45ec0e7997d43f266c3ce0c9fcbe > blob + 26e15d93b91bc42ee028fa8ecf60a8d1ac4dfdc9 > --- include/got_gotconfig.h > +++ include/got_gotconfig.h > @@ -29,3 +29,19 @@ const char *got_gotconfig_get_author(const struct got_ > */ > void got_gotconfig_get_remotes(int *, const struct got_remote_repo **, > const struct got_gotconfig *); > + > +/* > + * Obtain the filename of the allowed signers file. > + * Returns NULL if no configuration file is found or no allowed signers file > + * is configured. > + */ > +const char * > +got_gotconfig_get_allowed_signers_file(const struct got_gotconfig *); > + > +/* > + * Obtain the filename of the revoked signers file. > + * Returns NULL if no configuration file is found or no revoked signers file > + * is configured. > + */ > +const char * > +got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *); > blob - a8d0318ceaa7152627e8c8718ba039f8517bc3e4 > blob + 1cd6f349912d3e03ebbdccfd4beeeb54663af7fb > --- include/got_object.h > +++ include/got_object.h > @@ -351,4 +351,4 @@ const struct got_error *got_object_commit_add_parent(s > /* Create a new tag object in the repository. */ > const struct got_error *got_object_tag_create(struct got_object_id **, > const char *, struct got_object_id *, const char *, > - time_t, const char *, struct got_repository *); > + time_t, const char *, const char *, struct got_repository *, int verbosity); > blob - /dev/null > blob + e1eb576f115932bb52bb70a663a2facb02643ca9 (mode 644) > --- /dev/null > +++ include/got_tag.h > @@ -0,0 +1,28 @@ > +/* > + * Copyright (c) 2022 Josh Rickmar <jrick@zettaport.com> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +const struct got_error * > +got_tag_apply_unveil(void); > + > +const struct got_error * > +got_tag_sign_ssh(pid_t *, int *, int *, const char *, int); > + > +const char * > +got_tag_message_get_ssh_signature(const char *); > + > +const struct got_error * > +got_tag_verify_ssh(char **, struct got_tag_object *, const char *, const char *, > + const char *, int); > blob - /dev/null > blob + 618af333cee8c4bcb2b88cb3f4b031788f8f2761 (mode 644) > --- /dev/null > +++ lib/date.c > @@ -0,0 +1,35 @@ > +/* > + * Copyright (c) 2022 Josh Rickmar <jrick@zettaport.com> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <stdio.h> > + > +#include "got_date.h" > + > +void > +got_format_gmtoff(char *buf, size_t sz, time_t gmtoff) > +{ > + long long h, m; > + char sign = '+'; > + > + if (gmtoff < 0) { > + sign = '-'; > + gmtoff = -gmtoff; > + } > + > + h = (long long)gmtoff / 3600; > + m = ((long long)gmtoff - h*3600) / 60; > + snprintf(buf, sz, "%c%02lld%02lld", sign, h, m); > +} > blob - 3ffd653ef429fab490d06ba6a953185254e7c117 > blob + e88c9483b7d3b719c04835b3500183decbf835d1 > --- lib/error.c > +++ lib/error.c > @@ -217,6 +217,8 @@ static const struct got_error got_errors[] = { > { GOT_ERR_PATCH_FAILED, "patch failed to apply" }, > { GOT_ERR_FILEIDX_DUP_ENTRY, "duplicate file index entry" }, > { GOT_ERR_PIN_PACK, "could not pin pack file" }, > + { GOT_ERR_BAD_TAG_SIGNATURE, "invalid tag signature" }, > + { GOT_ERR_CANTVERIFY_TAG_SIGNATURE, "cannot verify signature" }, > }; > > static struct got_custom_error { > blob - 5e02aa1efeff0dd226e617da410a4663d8376d9a > blob + 39337ed4d9cbe7dfa5939b3f4dcb38793ccddfbd > --- lib/got_lib_gotconfig.h > +++ lib/got_lib_gotconfig.h > @@ -20,6 +20,8 @@ struct got_gotconfig { > char *author; > int nremotes; > struct got_remote_repo *remotes; > + char *allowed_signers_file; > + char *revoked_signers_file; > }; > > const struct got_error *got_gotconfig_read(struct got_gotconfig **, > blob - 6ffe646e98676cf9a0d19fe3ad27f3e63ab04fcc > blob + dac4ab973b68243e262fd1ae6482fffb6dc2bc57 > --- lib/got_lib_privsep.h > +++ lib/got_lib_privsep.h > @@ -172,6 +172,8 @@ enum got_imsg_type { > /* Messages related to gotconfig files. */ > GOT_IMSG_GOTCONFIG_PARSE_REQUEST, > GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST, > + GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, > + GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, > GOT_IMSG_GOTCONFIG_REMOTES_REQUEST, > GOT_IMSG_GOTCONFIG_INT_VAL, > GOT_IMSG_GOTCONFIG_STR_VAL, > @@ -760,6 +762,10 @@ const struct got_error *got_privsep_recv_gitconfig_rem > const struct got_error *got_privsep_send_gotconfig_parse_req(struct imsgbuf *, > int); > const struct got_error *got_privsep_send_gotconfig_author_req(struct imsgbuf *); > +const struct got_error *got_privsep_send_gotconfig_allowed_signers_req( > + struct imsgbuf *); > +const struct got_error *got_privsep_send_gotconfig_revoked_signers_req( > + struct imsgbuf *); > const struct got_error *got_privsep_send_gotconfig_remotes_req( > struct imsgbuf *); > const struct got_error *got_privsep_recv_gotconfig_str(char **, > blob - 5b602c9f5513aee64b98ca608535d5b85280ec42 > blob + 7fae8306f7aa444e25b71f0a95f8f151ec324a7f > --- lib/gotconfig.c > +++ lib/gotconfig.c > @@ -101,6 +101,24 @@ got_gotconfig_read(struct got_gotconfig **conf, const > if (err) > goto done; > > + err = got_privsep_send_gotconfig_allowed_signers_req(ibuf); > + if (err) > + goto done; > + > + err = got_privsep_recv_gotconfig_str(&(*conf)->allowed_signers_file, > + ibuf); > + if (err) > + goto done; > + > + err = got_privsep_send_gotconfig_revoked_signers_req(ibuf); > + if (err) > + goto done; > + > + err = got_privsep_recv_gotconfig_str(&(*conf)->revoked_signers_file, > + ibuf); > + if (err) > + goto done; > + > err = got_privsep_send_gotconfig_remotes_req(ibuf); > if (err) > goto done; > @@ -158,3 +176,15 @@ got_gotconfig_get_remotes(int *nremotes, const struct > *nremotes = conf->nremotes; > *remotes = conf->remotes; > } > + > +const char * > +got_gotconfig_get_allowed_signers_file(const struct got_gotconfig *conf) > +{ > + return conf->allowed_signers_file; > +} > + > +const char * > +got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *conf) > +{ > + return conf->revoked_signers_file; > +} > blob - 5036de1b9a6b491a1fc7c0358a03dcd9574f6cf3 > blob + 105e30ab2f4acad2244635c54c23003e67de8a60 > --- lib/object_create.c > +++ lib/object_create.c > @@ -17,6 +17,7 @@ > #include <sys/types.h> > #include <sys/stat.h> > #include <sys/queue.h> > +#include <sys/wait.h> > > #include <ctype.h> > #include <errno.h> > @@ -35,6 +36,7 @@ > #include "got_repository.h" > #include "got_opentemp.h" > #include "got_path.h" > +#include "got_tag.h" > > #include "got_lib_sha1.h" > #include "got_lib_deflate.h" > @@ -45,6 +47,8 @@ > > #include "got_lib_object_create.h" > > +#include "buf.h" > + > #ifndef nitems > #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) > #endif > @@ -608,7 +612,8 @@ done: > const struct got_error * > got_object_tag_create(struct got_object_id **id, > const char *tag_name, struct got_object_id *object_id, const char *tagger, > - time_t tagger_time, const char *tagmsg, struct got_repository *repo) > + time_t tagger_time, const char *tagmsg, const char *key_file, > + struct got_repository *repo, int verbosity) > { > const struct got_error *err = NULL; > SHA1_CTX sha1_ctx; > @@ -621,6 +626,7 @@ got_object_tag_create(struct got_object_id **id, > char *msg0 = NULL, *msg; > const char *obj_type_str; > int obj_type; > + BUF *buf = NULL; > > *id = NULL; > > @@ -747,6 +753,76 @@ got_object_tag_create(struct got_object_id **id, > } > tagsize += n; > > + if (key_file) { > + FILE *out; > + pid_t pid; > + size_t len; > + int in_fd, out_fd; > + int status; > + > + err = buf_alloc(&buf, 0); > + if (err) > + goto done; > + > + /* signed message */ > + err = buf_puts(&len, buf, obj_str); > + if (err) > + goto done; > + err = buf_puts(&len, buf, type_str); > + if (err) > + goto done; > + err = buf_puts(&len, buf, tag_str); > + if (err) > + goto done; > + err = buf_puts(&len, buf, tagger_str); > + if (err) > + goto done; > + err = buf_putc(buf, '\n'); > + if (err) > + goto done; > + err = buf_puts(&len, buf, msg); > + if (err) > + goto done; > + err = buf_putc(buf, '\n'); > + if (err) > + goto done; > + > + err = got_tag_sign_ssh(&pid, &in_fd, &out_fd, key_file, > + verbosity); > + if (err) > + goto done; > + if (buf_write_fd(buf, in_fd) == -1) { > + err = got_error_from_errno("write"); > + goto done; > + } > + if (close(in_fd) == -1) { > + err = got_error_from_errno("close"); > + goto done; > + } > + > + if (waitpid(pid, &status, 0) == -1) { > + err = got_error_from_errno("waitpid"); > + goto done; > + } > + > + out = fdopen(out_fd, "r"); > + if (out == NULL) { > + err = got_error_from_errno("fdopen"); > + goto done; > + } > + buf_empty(buf); > + err = buf_load(&buf, out); > + if (err) > + goto done; > + err = buf_putc(buf, '\0'); > + if (err) > + goto done; > + if (close(out_fd) == -1) { > + err = got_error_from_errno("close"); > + goto done; > + } > + } > + > len = strlen(msg); > SHA1Update(&sha1_ctx, msg, len); > n = fwrite(msg, 1, len, tagfile); > @@ -764,6 +840,17 @@ got_object_tag_create(struct got_object_id **id, > } > tagsize += n; > > + if (key_file && buf_len(buf) > 0) { > + len = buf_len(buf); > + SHA1Update(&sha1_ctx, buf_get(buf), len); > + n = fwrite(buf_get(buf), 1, len, tagfile); > + if (n != len) { > + err = got_ferror(tagfile, GOT_ERR_IO); > + goto done; > + } > + tagsize += n; > + } > + > *id = malloc(sizeof(**id)); > if (*id == NULL) { > err = got_error_from_errno("malloc"); > @@ -783,6 +870,8 @@ done: > free(header); > free(obj_str); > free(tagger_str); > + if (buf) > + buf_release(buf); > if (tagfile && fclose(tagfile) == EOF && err == NULL) > err = got_error_from_errno("fclose"); > if (err) { > blob - c0bdac7221a79c5ec97d1728e862406152d51eb9 > blob + 07acf70c2c9103549d8dd9f40e6a173d0bb20401 > --- lib/privsep.c > +++ lib/privsep.c > @@ -2365,6 +2365,28 @@ got_privsep_send_gotconfig_author_req(struct imsgbuf * > } > > const struct got_error * > +got_privsep_send_gotconfig_allowed_signers_req(struct imsgbuf *ibuf) > +{ > + if (imsg_compose(ibuf, > + GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1) > + return got_error_from_errno("imsg_compose " > + "GOTCONFIG_ALLOWEDSIGNERS_REQUEST"); > + > + return flush_imsg(ibuf); > +} > + > +const struct got_error * > +got_privsep_send_gotconfig_revoked_signers_req(struct imsgbuf *ibuf) > +{ > + if (imsg_compose(ibuf, > + GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST, 0, 0, -1, NULL, 0) == -1) > + return got_error_from_errno("imsg_compose " > + "GOTCONFIG_REVOKEDSIGNERS_REQUEST"); > + > + return flush_imsg(ibuf); > +} > + > +const struct got_error * > got_privsep_send_gotconfig_remotes_req(struct imsgbuf *ibuf) > { > if (imsg_compose(ibuf, > blob - /dev/null > blob + f7d4feb11e3d09e32eb54239c0dcbbae397cd363 (mode 644) > --- /dev/null > +++ lib/tag.c > @@ -0,0 +1,414 @@ > +/* > + * Copyright (c) 2022 Josh Rickmar <jrick@zettaport.com> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <sys/socket.h> > +#include <sys/queue.h> > +#include <sys/wait.h> > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <fcntl.h> > +#include <unistd.h> > +#include <string.h> > +#include <err.h> > +#include <assert.h> > +#include <sha1.h> > + > +#include "got_error.h" > +#include "got_date.h" > +#include "got_object.h" > +#include "got_opentemp.h" > + > +#include "got_tag.h" > + > +#include "buf.h" > + > +#ifndef MIN > +#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) > +#endif > + > +#ifndef nitems > +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) > +#endif > + > +#ifndef GOT_TAG_PATH_SSH_KEYGEN > +#define GOT_TAG_PATH_SSH_KEYGEN "/usr/bin/ssh-keygen" > +#endif > + > +#ifndef GOT_TAG_PATH_SIGNIFY > +#define GOT_TAG_PATH_SIGNIFY "/usr/bin/signify" > +#endif > + > +const struct got_error * > +got_tag_apply_unveil() > +{ > + if (unveil(GOT_TAG_PATH_SSH_KEYGEN, "x") != 0) { > + return got_error_from_errno2("unveil", > + GOT_TAG_PATH_SSH_KEYGEN); > + } > + if (unveil(GOT_TAG_PATH_SIGNIFY, "x") != 0) { > + return got_error_from_errno2("unveil", > + GOT_TAG_PATH_SIGNIFY); > + } > + > + return NULL; > +} > + > +const struct got_error * > +got_tag_sign_ssh(pid_t *newpid, int *in_fd, int *out_fd, const char* key_file, > + int verbosity) > +{ > + const struct got_error *error = NULL; > + int pid, in_pfd[2], out_pfd[2]; > + const char* argv[11]; Same here. > + int i = 0, j; > + > + *newpid = -1; > + *in_fd = -1; > + *out_fd = -1; > + > + argv[i++] = GOT_TAG_PATH_SSH_KEYGEN; > + argv[i++] = "-Y"; > + argv[i++] = "sign"; > + argv[i++] = "-f"; > + argv[i++] = key_file; > + argv[i++] = "-n"; > + argv[i++] = "git"; > + if (verbosity <= 0) { > + argv[i++] = "-q"; > + } else { > + /* ssh(1) allows up to 3 "-v" options. */ > + for (j = 0; j < MIN(3, verbosity); j++) > + argv[i++] = "-v"; > + } > + argv[i++] = NULL; > + assert(i <= nitems(argv)); > + > + if (pipe2(in_pfd, 0 /*O_NONBLOCK|O_CLOEXEC*/) == -1) > + return got_error_from_errno("pipe2"); > + if (pipe2(out_pfd, 0 /*O_NONBLOCK|O_CLOEXEC*/) == -1) > + return got_error_from_errno("pipe2"); > + > + pid = fork(); > + if (pid == -1) { > + error = got_error_from_errno("fork"); > + close(in_pfd[0]); > + close(in_pfd[1]); > + close(out_pfd[0]); > + close(out_pfd[1]); > + return error; > + } else if (pid == 0) { > + if (close(in_pfd[1]) == -1) > + err(1, "close"); > + if (close(out_pfd[1]) == -1) > + err(1, "close"); > + if (dup2(in_pfd[0], 0) == -1) > + err(1, "dup2"); > + if (dup2(out_pfd[0], 1) == -1) > + err(1, "dup2"); > + if (execv(GOT_TAG_PATH_SSH_KEYGEN, (char **const)argv) == -1) > + err(1, "execv"); > + abort(); /* not reached */ > + } > + if (close(in_pfd[0]) == -1) > + return got_error_from_errno("close"); > + if (close(out_pfd[0]) == -1) > + return got_error_from_errno("close"); > + *newpid = pid; > + *in_fd = in_pfd[1]; > + *out_fd = out_pfd[1]; > + return NULL; > +} > + > +static char * > +signer_identity(const char *tagger) > +{ > + char *lt, *gt; > + > + lt = strstr(tagger, " <"); > + gt = strrchr(tagger, '>'); > + if (lt && gt && lt+1 < gt) > + return strndup(lt+2, gt-lt-2); > + return NULL; > +} > + > +static const char* BEGIN_SSH_SIG = "-----BEGIN SSH SIGNATURE-----\n"; > +static const char* END_SSH_SIG = "-----END SSH SIGNATURE-----\n"; > + > +//static const int SIG_KIND_SSH = 1; > +//static const int SIG_KIND_SIGNIFY = 2; did you miss something here? > + > +const char * > +got_tag_message_get_ssh_signature(const char *tagmsg) > +{ > + const char *s = tagmsg, *begin = NULL, *end = NULL; > + > + while ((s = strstr(s, BEGIN_SSH_SIG)) != NULL) { > + begin = s; > + s += strlen(BEGIN_SSH_SIG); > + } > + if (begin) > + end = strstr(begin+strlen(BEGIN_SSH_SIG), END_SSH_SIG); > + if (end == NULL) > + return NULL; > + return (end[strlen(END_SSH_SIG)] == '\0') ? begin : NULL; > +} > + > +static const struct got_error * > +got_tag_write_signed_data(BUF *buf, struct got_tag_object *tag, > + const char *start_sig) > +{ > + const struct got_error *err = NULL; > + struct got_object_id *id; > + char *id_str = NULL; > + char *tagger = NULL; > + const char *tagmsg; > + char gmtoff[6]; > + size_t len; > + > + id = got_object_tag_get_object_id(tag); > + err = got_object_id_str(&id_str, id); > + if (err) > + goto done; > + > + const char *type_label = NULL; > + switch (got_object_tag_get_object_type(tag)) { > + case GOT_OBJ_TYPE_BLOB: > + type_label = GOT_OBJ_LABEL_BLOB; > + break; > + case GOT_OBJ_TYPE_TREE: > + type_label = GOT_OBJ_LABEL_TREE; > + break; > + case GOT_OBJ_TYPE_COMMIT: > + type_label = GOT_OBJ_LABEL_COMMIT; > + break; > + case GOT_OBJ_TYPE_TAG: > + type_label = GOT_OBJ_LABEL_TAG; > + break; > + default: > + break; > + } > + got_format_gmtoff(gmtoff, sizeof(gmtoff), > + got_object_tag_get_tagger_gmtoff(tag)); > + if (asprintf(&tagger, "%s %lld %s", got_object_tag_get_tagger(tag), > + got_object_tag_get_tagger_time(tag), gmtoff) == -1) { > + err = got_error_from_errno("asprintf"); > + goto done; > + } > + > + err = buf_puts(&len, buf, GOT_TAG_LABEL_OBJECT); > + if (err) > + goto done; > + err = buf_puts(&len, buf, id_str); > + if (err) > + goto done; > + err = buf_putc(buf, '\n'); > + if (err) > + goto done; > + err = buf_puts(&len, buf, GOT_TAG_LABEL_TYPE); > + if (err) > + goto done; > + err = buf_puts(&len, buf, type_label); > + if (err) > + goto done; > + err = buf_putc(buf, '\n'); > + if (err) > + goto done; > + err = buf_puts(&len, buf, GOT_TAG_LABEL_TAG); > + if (err) > + goto done; > + err = buf_puts(&len, buf, got_object_tag_get_name(tag)); > + if (err) > + goto done; > + err = buf_putc(buf, '\n'); > + if (err) > + goto done; > + err = buf_puts(&len, buf, GOT_TAG_LABEL_TAGGER); > + if (err) > + goto done; > + err = buf_puts(&len, buf, tagger); > + if (err) > + goto done; > + err = buf_puts(&len, buf, "\n"); > + if (err) > + goto done; > + tagmsg = got_object_tag_get_message(tag); > + err = buf_append(&len, buf, tagmsg, start_sig-tagmsg); > + if (err) > + goto done; > + > +done: > + free(id_str); > + free(tagger); > + return err; > +} > + > +const struct got_error * > +got_tag_verify_ssh(char **msg, struct got_tag_object *tag, > + const char *start_sig, const char* allowed_signers, const char* revoked, > + int verbosity) > +{ > + const struct got_error *error = NULL; > + const char* argv[17]; > + int pid, status, in_pfd[2], out_pfd[2]; > + char* parsed_identity = NULL; > + const char *identity; > + char* tmppath = NULL; > + FILE *tmpsig, *out = NULL; > + BUF *buf; > + int i = 0, j; > + > + *msg = NULL; > + > + error = got_opentemp_named(&tmppath, &tmpsig, > + GOT_TMPDIR_STR "/got-tagsig"); > + if (error) > + goto done; > + ---------------------- > + got_opentemp(); > + if (tmpsig == NULL) { > + error = got_error_from_errno("got_opentemp"); > + goto done; > + } this doesn't look right. i don't think it should exist ---------------------- > + > + identity = got_object_tag_get_tagger(tag); > + parsed_identity = signer_identity(identity); > + if (parsed_identity != NULL) > + identity = parsed_identity; > + > + if (fputs(start_sig, tmpsig) == EOF) { > + error = got_error_from_errno("fputs"); > + goto done; > + } > + if (fflush(tmpsig) == EOF) { > + error = got_error_from_errno("fflush"); > + goto done; > + } > + > + error = buf_alloc(&buf, 0); > + if (error) > + goto done; > + error = got_tag_write_signed_data(buf, tag, start_sig); > + if (error) > + goto done; > + > + argv[i++] = GOT_TAG_PATH_SSH_KEYGEN; > + argv[i++] = "-Y"; > + argv[i++] = "verify"; > + argv[i++] = "-f"; > + argv[i++] = allowed_signers; > + argv[i++] = "-I"; > + argv[i++] = identity; > + argv[i++] = "-n"; > + argv[i++] = "git"; > + argv[i++] = "-s"; > + argv[i++] = tmppath; > + if (revoked) { > + argv[i++] = "-r"; > + argv[i++] = revoked; > + } > + if (verbosity > 0) { > + /* ssh(1) allows up to 3 "-v" options. */ > + for (j = 0; j < MIN(3, verbosity); j++) > + argv[i++] = "-v"; > + } > + argv[i++] = NULL; > + assert(i <= nitems(argv)); > + > + if (pipe2(in_pfd, 0 /*O_NONBLOCK|O_CLOEXEC*/) == -1) { > + error = got_error_from_errno("pipe2"); > + goto done; > + } > + if (pipe2(out_pfd, 0 /*O_NONBLOCK|O_CLOEXEC*/) == -1) { > + error = got_error_from_errno("pipe2"); > + goto done; > + } > + > + pid = fork(); > + if (pid == -1) { > + error = got_error_from_errno("fork"); > + close(in_pfd[0]); > + close(in_pfd[1]); > + close(out_pfd[0]); > + close(out_pfd[1]); > + return error; > + } else if (pid == 0) { > + if (close(in_pfd[1]) == -1) > + err(1, "close"); > + if (close(out_pfd[1]) == -1) > + err(1, "close"); > + if (dup2(in_pfd[0], 0) == -1) > + err(1, "dup2"); > + if (dup2(out_pfd[0], 1) == -1) > + err(1, "dup2"); > + if (execv(GOT_TAG_PATH_SSH_KEYGEN, (char **const)argv) == -1) > + err(1, "execv"); > + abort(); /* not reached */ > + } > + if (close(in_pfd[0]) == -1) { > + error = got_error_from_errno("close"); > + goto done; > + } > + if (close(out_pfd[0]) == -1) { > + error = got_error_from_errno("close"); > + goto done; > + } > + if (buf_write_fd(buf, in_pfd[1]) == -1) { > + error = got_error_from_errno("write"); > + goto done; > + } > + if (close(in_pfd[1]) == -1) { > + error = got_error_from_errno("close"); > + goto done; > + } > + if (waitpid(pid, &status, 0) == -1) { > + error = got_error_from_errno("waitpid"); > + goto done; > + } > + if (!WIFEXITED(status)) { > + error = got_error(GOT_ERR_BAD_TAG_SIGNATURE); > + goto done; > + } > + > + out = fdopen(out_pfd[1], "r"); > + if (out == NULL) { > + error = got_error_from_errno("fdopen"); > + goto done; > + } > + error = buf_load(&buf, out); > + if (error) > + goto done; > + error = buf_putc(buf, '\0'); > + if (error) > + goto done; > + if (close(out_pfd[1]) == -1) { > + error = got_error_from_errno("close"); > + goto done; > + } > + out = NULL; > + *msg = buf_get(buf); > + > +done: > + free(parsed_identity); > + free(tmppath); > + if (tmpsig && fclose(tmpsig) == EOF && error == NULL) > + error = got_error_from_errno("fclose"); > + if (out && fclose(out) == EOF && error == NULL) > + error = got_error_from_errno("fclose"); > + return error; > +} > blob - aa2c97552358174249a7361aba78c785626d6b7f > blob + be0d93073a8d7779e487b6a2d12bad1e6c9721d4 > --- libexec/got-read-gotconfig/got-read-gotconfig.c > +++ libexec/got-read-gotconfig/got-read-gotconfig.c > @@ -548,6 +548,24 @@ main(int argc, char *argv[]) > err = send_gotconfig_str(&ibuf, > gotconfig->author ? gotconfig->author : ""); > break; > + case GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST: > + if (gotconfig == NULL) { > + err = got_error(GOT_ERR_PRIVSEP_MSG); > + break; > + } > + err = send_gotconfig_str(&ibuf, > + gotconfig->allowed_signers_file ? > + gotconfig->allowed_signers_file : ""); > + break; > + case GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST: > + if (gotconfig == NULL) { > + err = got_error(GOT_ERR_PRIVSEP_MSG); > + break; > + } > + err = send_gotconfig_str(&ibuf, > + gotconfig->revoked_signers_file ? > + gotconfig->revoked_signers_file : ""); > + break; > case GOT_IMSG_GOTCONFIG_REMOTES_REQUEST: > if (gotconfig == NULL) { > err = got_error(GOT_ERR_PRIVSEP_MSG); > blob - 1ce499222101a45de399bd433825c767df869d91 > blob + 504e691250732f7b2baee47695fc1794127b2adb > --- libexec/got-read-gotconfig/gotconfig.h > +++ libexec/got-read-gotconfig/gotconfig.h > @@ -1,4 +1,5 @@ > /* > + * Copyright (c) 2022 Josh Rickmar <jrick@zettaport.com> > * Copyright (c) 2020, 2021 Tracey Emery <tracey@openbsd.org> > * Copyright (c) 2020 Stefan Sperling <stsp@openbsd.org> > * > @@ -66,6 +67,8 @@ struct gotconfig { > char *author; > struct gotconfig_remote_repo_list remotes; > int nremotes; > + char *allowed_signers_file; > + char *revoked_signers_file; > }; > > /* > blob - b9a0bd38cabe5d893cbbb04c482578a895a094ed > blob + 85fc623c3bd3ebda367919af6ac405ae817a88fc > --- libexec/got-read-gotconfig/parse.y > +++ libexec/got-read-gotconfig/parse.y > @@ -99,7 +99,8 @@ typedef struct { > > %token ERROR > %token REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH > -%token AUTHOR FETCH_ALL_BRANCHES REFERENCE FETCH SEND > +%token AUTHOR ALLOWED_SIGNERS REVOKED_SIGNERS FETCH_ALL_BRANCHES REFERENCE > +%token FETCH SEND > %token <v.string> STRING > %token <v.number> NUMBER > %type <v.number> boolean portplain > @@ -113,6 +114,7 @@ grammar : /* empty */ > | grammar '\n' > | grammar author '\n' > | grammar remote '\n' > + | grammar allowed_signers '\n' > ; > boolean : STRING { > if (strcasecmp($1, "true") == 0 || > @@ -306,6 +308,14 @@ author : AUTHOR STRING { > gotconfig.author = $2; > } > ; > +allowed_signers : ALLOWED_SIGNERS STRING { > + gotconfig.allowed_signers_file = $2; > + } > + ; > +revoked_signers : REVOKED_SIGNERS STRING { > + gotconfig.revoked_signers_file = $2; > + } > + ; > optnl : '\n' optnl > | /* empty */ > ; > @@ -354,6 +364,7 @@ lookup(char *s) > { > /* This has to be sorted always. */ > static const struct keywords keywords[] = { > + {"allowed_signers", ALLOWED_SIGNERS}, > {"author", AUTHOR}, > {"branch", BRANCH}, > {"fetch", FETCH}, > @@ -364,6 +375,7 @@ lookup(char *s) > {"reference", REFERENCE}, > {"remote", REMOTE}, > {"repository", REPOSITORY}, > + {"revoked_signers", REVOKED_SIGNERS}, > {"send", SEND}, > {"server", SERVER}, > }; > @@ -791,6 +803,8 @@ gotconfig_free(struct gotconfig *conf) > struct gotconfig_remote_repo *remote; > > free(conf->author); > + free(conf->allowed_signers_file); > + free(conf->revoked_signers_file); > while (!TAILQ_EMPTY(&conf->remotes)) { > remote = TAILQ_FIRST(&conf->remotes); > TAILQ_REMOVE(&conf->remotes, remote, entry); > blob - 0215869fd1a3678fe92c416a609faf3e875f0a34 > blob + e3a920cac7fae89fc7521957115fff5d80f21cdc > --- regress/fetch/Makefile > +++ regress/fetch/Makefile > @@ -4,7 +4,8 @@ PROG = fetch_test > SRCS = error.c privsep.c reference.c sha1.c object.c object_parse.c path.c \ > opentemp.c repository.c lockfile.c object_cache.c pack.c inflate.c \ > deflate.c delta.c delta_cache.c object_idset.c object_create.c \ > - fetch.c gotconfig.c dial.c fetch_test.c bloom.c murmurhash2.c > + fetch.c gotconfig.c dial.c fetch_test.c bloom.c murmurhash2.c tag.c \ > + buf.c date.c > > CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib > LDADD = -lutil -lz -lm > blob - ba79d5e787ada9939dea4f62aae062cea501f845 > blob + 1c8c7b124a59736d122d6b3b73c43be42cd29173 > --- tog/Makefile > +++ tog/Makefile > @@ -12,7 +12,7 @@ SRCS= tog.c blame.c commit_graph.c delta.c diff.c \ > gotconfig.c diff_main.c diff_atomize_text.c \ > diff_myers.c diff_output.c diff_output_plain.c \ > diff_output_unidiff.c diff_output_edscript.c \ > - diff_patience.c bloom.c murmurhash2.c > + diff_patience.c bloom.c murmurhash2.c tag.c date.c > MAN = ${PROG}.1 > > CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib > -- Tracey Emery
Tag signing with SSH signatures