Merge branch 'fs/ssh-signing-key-lifetime'
Extend the signing of objects with SSH keys and learn to pay attention to the key validity time range when verifying. * fs/ssh-signing-key-lifetime: ssh signing: verify ssh-keygen in test prereq ssh signing: make fmt-merge-msg consider key lifetime ssh signing: make verify-tag consider key lifetime ssh signing: make git log verify key lifetime ssh signing: make verify-commit consider key lifetime ssh signing: add key lifetime test prereqs ssh signing: use sigc struct to pass payload t/fmt-merge-msg: make gpgssh tests more specific t/fmt-merge-msg: do not redirect stderrmaint
commit
d2f0b72759
|
@ -64,6 +64,11 @@ A repository that only allows signed commits can store the file
|
||||||
in the repository itself using a path relative to the top-level of the working tree.
|
in the repository itself using a path relative to the top-level of the working tree.
|
||||||
This way only committers with an already valid key can add or change keys in the keyring.
|
This way only committers with an already valid key can add or change keys in the keyring.
|
||||||
+
|
+
|
||||||
|
Since OpensSSH 8.8 this file allows specifying a key lifetime using valid-after &
|
||||||
|
valid-before options. Git will mark signatures as valid if the signing key was
|
||||||
|
valid at the time of the signatures creation. This allows users to change a
|
||||||
|
signing key without invalidating all previously made signatures.
|
||||||
|
+
|
||||||
Using a SSH CA key with the cert-authority option
|
Using a SSH CA key with the cert-authority option
|
||||||
(see ssh-keygen(1) "CERTIFICATES") is also valid.
|
(see ssh-keygen(1) "CERTIFICATES") is also valid.
|
||||||
|
|
||||||
|
|
|
@ -769,8 +769,10 @@ static void prepare_push_cert_sha1(struct child_process *proc)
|
||||||
memset(&sigcheck, '\0', sizeof(sigcheck));
|
memset(&sigcheck, '\0', sizeof(sigcheck));
|
||||||
|
|
||||||
bogs = parse_signed_buffer(push_cert.buf, push_cert.len);
|
bogs = parse_signed_buffer(push_cert.buf, push_cert.len);
|
||||||
check_signature(push_cert.buf, bogs, push_cert.buf + bogs,
|
sigcheck.payload = xmemdupz(push_cert.buf, bogs);
|
||||||
push_cert.len - bogs, &sigcheck);
|
sigcheck.payload_len = bogs;
|
||||||
|
check_signature(&sigcheck, push_cert.buf + bogs,
|
||||||
|
push_cert.len - bogs);
|
||||||
|
|
||||||
nonce_status = check_nonce(push_cert.buf, bogs);
|
nonce_status = check_nonce(push_cert.buf, bogs);
|
||||||
}
|
}
|
||||||
|
|
6
commit.c
6
commit.c
|
@ -1212,8 +1212,10 @@ int check_commit_signature(const struct commit *commit, struct signature_check *
|
||||||
|
|
||||||
if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
|
if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
|
||||||
goto out;
|
goto out;
|
||||||
ret = check_signature(payload.buf, payload.len, signature.buf,
|
|
||||||
signature.len, sigc);
|
sigc->payload_type = SIGNATURE_PAYLOAD_COMMIT;
|
||||||
|
sigc->payload = strbuf_detach(&payload, &sigc->payload_len);
|
||||||
|
ret = check_signature(sigc, signature.buf, signature.len);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
strbuf_release(&payload);
|
strbuf_release(&payload);
|
||||||
|
|
|
@ -533,8 +533,9 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
|
||||||
else {
|
else {
|
||||||
buf = payload.buf;
|
buf = payload.buf;
|
||||||
len = payload.len;
|
len = payload.len;
|
||||||
if (check_signature(payload.buf, payload.len, sig.buf,
|
sigc.payload_type = SIGNATURE_PAYLOAD_TAG;
|
||||||
sig.len, &sigc) &&
|
sigc.payload = strbuf_detach(&payload, &sigc.payload_len);
|
||||||
|
if (check_signature(&sigc, sig.buf, sig.len) &&
|
||||||
!sigc.output)
|
!sigc.output)
|
||||||
strbuf_addstr(&sig, "gpg verification failed.\n");
|
strbuf_addstr(&sig, "gpg verification failed.\n");
|
||||||
else
|
else
|
||||||
|
|
|
@ -19,8 +19,8 @@ struct gpg_format {
|
||||||
const char **verify_args;
|
const char **verify_args;
|
||||||
const char **sigs;
|
const char **sigs;
|
||||||
int (*verify_signed_buffer)(struct signature_check *sigc,
|
int (*verify_signed_buffer)(struct signature_check *sigc,
|
||||||
struct gpg_format *fmt, const char *payload,
|
struct gpg_format *fmt,
|
||||||
size_t payload_size, const char *signature,
|
const char *signature,
|
||||||
size_t signature_size);
|
size_t signature_size);
|
||||||
int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
|
int (*sign_buffer)(struct strbuf *buffer, struct strbuf *signature,
|
||||||
const char *signing_key);
|
const char *signing_key);
|
||||||
|
@ -53,12 +53,12 @@ static const char *ssh_sigs[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int verify_gpg_signed_buffer(struct signature_check *sigc,
|
static int verify_gpg_signed_buffer(struct signature_check *sigc,
|
||||||
struct gpg_format *fmt, const char *payload,
|
struct gpg_format *fmt,
|
||||||
size_t payload_size, const char *signature,
|
const char *signature,
|
||||||
size_t signature_size);
|
size_t signature_size);
|
||||||
static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
struct gpg_format *fmt, const char *payload,
|
struct gpg_format *fmt,
|
||||||
size_t payload_size, const char *signature,
|
const char *signature,
|
||||||
size_t signature_size);
|
size_t signature_size);
|
||||||
static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
|
static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
|
||||||
const char *signing_key);
|
const char *signing_key);
|
||||||
|
@ -314,8 +314,8 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verify_gpg_signed_buffer(struct signature_check *sigc,
|
static int verify_gpg_signed_buffer(struct signature_check *sigc,
|
||||||
struct gpg_format *fmt, const char *payload,
|
struct gpg_format *fmt,
|
||||||
size_t payload_size, const char *signature,
|
const char *signature,
|
||||||
size_t signature_size)
|
size_t signature_size)
|
||||||
{
|
{
|
||||||
struct child_process gpg = CHILD_PROCESS_INIT;
|
struct child_process gpg = CHILD_PROCESS_INIT;
|
||||||
|
@ -343,14 +343,13 @@ static int verify_gpg_signed_buffer(struct signature_check *sigc,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
sigchain_push(SIGPIPE, SIG_IGN);
|
sigchain_push(SIGPIPE, SIG_IGN);
|
||||||
ret = pipe_command(&gpg, payload, payload_size, &gpg_stdout, 0,
|
ret = pipe_command(&gpg, sigc->payload, sigc->payload_len, &gpg_stdout, 0,
|
||||||
&gpg_stderr, 0);
|
&gpg_stderr, 0);
|
||||||
sigchain_pop(SIGPIPE);
|
sigchain_pop(SIGPIPE);
|
||||||
|
|
||||||
delete_tempfile(&temp);
|
delete_tempfile(&temp);
|
||||||
|
|
||||||
ret |= !strstr(gpg_stdout.buf, "\n[GNUPG:] GOODSIG ");
|
ret |= !strstr(gpg_stdout.buf, "\n[GNUPG:] GOODSIG ");
|
||||||
sigc->payload = xmemdupz(payload, payload_size);
|
|
||||||
sigc->output = strbuf_detach(&gpg_stderr, NULL);
|
sigc->output = strbuf_detach(&gpg_stderr, NULL);
|
||||||
sigc->gpg_status = strbuf_detach(&gpg_stdout, NULL);
|
sigc->gpg_status = strbuf_detach(&gpg_stdout, NULL);
|
||||||
|
|
||||||
|
@ -426,8 +425,8 @@ cleanup:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
struct gpg_format *fmt, const char *payload,
|
struct gpg_format *fmt,
|
||||||
size_t payload_size, const char *signature,
|
const char *signature,
|
||||||
size_t signature_size)
|
size_t signature_size)
|
||||||
{
|
{
|
||||||
struct child_process ssh_keygen = CHILD_PROCESS_INIT;
|
struct child_process ssh_keygen = CHILD_PROCESS_INIT;
|
||||||
|
@ -440,6 +439,13 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
struct strbuf ssh_principals_err = STRBUF_INIT;
|
struct strbuf ssh_principals_err = STRBUF_INIT;
|
||||||
struct strbuf ssh_keygen_out = STRBUF_INIT;
|
struct strbuf ssh_keygen_out = STRBUF_INIT;
|
||||||
struct strbuf ssh_keygen_err = STRBUF_INIT;
|
struct strbuf ssh_keygen_err = STRBUF_INIT;
|
||||||
|
struct strbuf verify_time = STRBUF_INIT;
|
||||||
|
const struct date_mode verify_date_mode = {
|
||||||
|
.type = DATE_STRFTIME,
|
||||||
|
.strftime_fmt = "%Y%m%d%H%M%S",
|
||||||
|
/* SSH signing key validity has no timezone information - Use the local timezone */
|
||||||
|
.local = 1,
|
||||||
|
};
|
||||||
|
|
||||||
if (!ssh_allowed_signers) {
|
if (!ssh_allowed_signers) {
|
||||||
error(_("gpg.ssh.allowedSignersFile needs to be configured and exist for ssh signature verification"));
|
error(_("gpg.ssh.allowedSignersFile needs to be configured and exist for ssh signature verification"));
|
||||||
|
@ -457,11 +463,16 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sigc->payload_timestamp)
|
||||||
|
strbuf_addf(&verify_time, "-Overify-time=%s",
|
||||||
|
show_date(sigc->payload_timestamp, 0, &verify_date_mode));
|
||||||
|
|
||||||
/* Find the principal from the signers */
|
/* Find the principal from the signers */
|
||||||
strvec_pushl(&ssh_keygen.args, fmt->program,
|
strvec_pushl(&ssh_keygen.args, fmt->program,
|
||||||
"-Y", "find-principals",
|
"-Y", "find-principals",
|
||||||
"-f", ssh_allowed_signers,
|
"-f", ssh_allowed_signers,
|
||||||
"-s", buffer_file->filename.buf,
|
"-s", buffer_file->filename.buf,
|
||||||
|
verify_time.buf,
|
||||||
NULL);
|
NULL);
|
||||||
ret = pipe_command(&ssh_keygen, NULL, 0, &ssh_principals_out, 0,
|
ret = pipe_command(&ssh_keygen, NULL, 0, &ssh_principals_out, 0,
|
||||||
&ssh_principals_err, 0);
|
&ssh_principals_err, 0);
|
||||||
|
@ -479,8 +490,9 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
"-Y", "check-novalidate",
|
"-Y", "check-novalidate",
|
||||||
"-n", "git",
|
"-n", "git",
|
||||||
"-s", buffer_file->filename.buf,
|
"-s", buffer_file->filename.buf,
|
||||||
|
verify_time.buf,
|
||||||
NULL);
|
NULL);
|
||||||
pipe_command(&ssh_keygen, payload, payload_size,
|
pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
|
||||||
&ssh_keygen_out, 0, &ssh_keygen_err, 0);
|
&ssh_keygen_out, 0, &ssh_keygen_err, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -513,6 +525,7 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
"-f", ssh_allowed_signers,
|
"-f", ssh_allowed_signers,
|
||||||
"-I", principal,
|
"-I", principal,
|
||||||
"-s", buffer_file->filename.buf,
|
"-s", buffer_file->filename.buf,
|
||||||
|
verify_time.buf,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (ssh_revocation_file) {
|
if (ssh_revocation_file) {
|
||||||
|
@ -526,7 +539,7 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
}
|
}
|
||||||
|
|
||||||
sigchain_push(SIGPIPE, SIG_IGN);
|
sigchain_push(SIGPIPE, SIG_IGN);
|
||||||
ret = pipe_command(&ssh_keygen, payload, payload_size,
|
ret = pipe_command(&ssh_keygen, sigc->payload, sigc->payload_len,
|
||||||
&ssh_keygen_out, 0, &ssh_keygen_err, 0);
|
&ssh_keygen_out, 0, &ssh_keygen_err, 0);
|
||||||
sigchain_pop(SIGPIPE);
|
sigchain_pop(SIGPIPE);
|
||||||
|
|
||||||
|
@ -540,7 +553,6 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sigc->payload = xmemdupz(payload, payload_size);
|
|
||||||
strbuf_stripspace(&ssh_keygen_out, 0);
|
strbuf_stripspace(&ssh_keygen_out, 0);
|
||||||
strbuf_stripspace(&ssh_keygen_err, 0);
|
strbuf_stripspace(&ssh_keygen_err, 0);
|
||||||
/* Add stderr outputs to show the user actual ssh-keygen errors */
|
/* Add stderr outputs to show the user actual ssh-keygen errors */
|
||||||
|
@ -558,12 +570,48 @@ out:
|
||||||
strbuf_release(&ssh_principals_err);
|
strbuf_release(&ssh_principals_err);
|
||||||
strbuf_release(&ssh_keygen_out);
|
strbuf_release(&ssh_keygen_out);
|
||||||
strbuf_release(&ssh_keygen_err);
|
strbuf_release(&ssh_keygen_err);
|
||||||
|
strbuf_release(&verify_time);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int check_signature(const char *payload, size_t plen, const char *signature,
|
static int parse_payload_metadata(struct signature_check *sigc)
|
||||||
size_t slen, struct signature_check *sigc)
|
{
|
||||||
|
const char *ident_line = NULL;
|
||||||
|
size_t ident_len;
|
||||||
|
struct ident_split ident;
|
||||||
|
const char *signer_header;
|
||||||
|
|
||||||
|
switch (sigc->payload_type) {
|
||||||
|
case SIGNATURE_PAYLOAD_COMMIT:
|
||||||
|
signer_header = "committer";
|
||||||
|
break;
|
||||||
|
case SIGNATURE_PAYLOAD_TAG:
|
||||||
|
signer_header = "tagger";
|
||||||
|
break;
|
||||||
|
case SIGNATURE_PAYLOAD_UNDEFINED:
|
||||||
|
case SIGNATURE_PAYLOAD_PUSH_CERT:
|
||||||
|
/* Ignore payloads we don't want to parse */
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
BUG("invalid value for sigc->payload_type");
|
||||||
|
}
|
||||||
|
|
||||||
|
ident_line = find_commit_header(sigc->payload, signer_header, &ident_len);
|
||||||
|
if (!ident_line || !ident_len)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (split_ident_line(&ident, ident_line, ident_len))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!sigc->payload_timestamp && ident.date_begin && ident.date_end)
|
||||||
|
sigc->payload_timestamp = parse_timestamp(ident.date_begin, NULL, 10);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_signature(struct signature_check *sigc,
|
||||||
|
const char *signature, size_t slen)
|
||||||
{
|
{
|
||||||
struct gpg_format *fmt;
|
struct gpg_format *fmt;
|
||||||
int status;
|
int status;
|
||||||
|
@ -575,8 +623,10 @@ int check_signature(const char *payload, size_t plen, const char *signature,
|
||||||
if (!fmt)
|
if (!fmt)
|
||||||
die(_("bad/incompatible signature '%s'"), signature);
|
die(_("bad/incompatible signature '%s'"), signature);
|
||||||
|
|
||||||
status = fmt->verify_signed_buffer(sigc, fmt, payload, plen, signature,
|
if (parse_payload_metadata(sigc))
|
||||||
slen);
|
return 1;
|
||||||
|
|
||||||
|
status = fmt->verify_signed_buffer(sigc, fmt, signature, slen);
|
||||||
|
|
||||||
if (status && !sigc->output)
|
if (status && !sigc->output)
|
||||||
return !!status;
|
return !!status;
|
||||||
|
@ -593,7 +643,7 @@ void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
|
||||||
sigc->output;
|
sigc->output;
|
||||||
|
|
||||||
if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
|
if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
|
||||||
fputs(sigc->payload, stdout);
|
fwrite(sigc->payload, 1, sigc->payload_len, stdout);
|
||||||
|
|
||||||
if (output)
|
if (output)
|
||||||
fputs(output, stderr);
|
fputs(output, stderr);
|
||||||
|
|
|
@ -15,8 +15,18 @@ enum signature_trust_level {
|
||||||
TRUST_ULTIMATE,
|
TRUST_ULTIMATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum payload_type {
|
||||||
|
SIGNATURE_PAYLOAD_UNDEFINED,
|
||||||
|
SIGNATURE_PAYLOAD_COMMIT,
|
||||||
|
SIGNATURE_PAYLOAD_TAG,
|
||||||
|
SIGNATURE_PAYLOAD_PUSH_CERT,
|
||||||
|
};
|
||||||
|
|
||||||
struct signature_check {
|
struct signature_check {
|
||||||
char *payload;
|
char *payload;
|
||||||
|
size_t payload_len;
|
||||||
|
enum payload_type payload_type;
|
||||||
|
timestamp_t payload_timestamp;
|
||||||
char *output;
|
char *output;
|
||||||
char *gpg_status;
|
char *gpg_status;
|
||||||
|
|
||||||
|
@ -70,9 +80,8 @@ const char *get_signing_key(void);
|
||||||
* Either a GPG KeyID or a SSH Key Fingerprint
|
* Either a GPG KeyID or a SSH Key Fingerprint
|
||||||
*/
|
*/
|
||||||
const char *get_signing_key_id(void);
|
const char *get_signing_key_id(void);
|
||||||
int check_signature(const char *payload, size_t plen,
|
int check_signature(struct signature_check *sigc,
|
||||||
const char *signature, size_t slen,
|
const char *signature, size_t slen);
|
||||||
struct signature_check *sigc);
|
|
||||||
void print_signature_buffer(const struct signature_check *sigc,
|
void print_signature_buffer(const struct signature_check *sigc,
|
||||||
unsigned flags);
|
unsigned flags);
|
||||||
|
|
||||||
|
|
10
log-tree.c
10
log-tree.c
|
@ -513,8 +513,9 @@ static void show_signature(struct rev_info *opt, struct commit *commit)
|
||||||
if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
|
if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
status = check_signature(payload.buf, payload.len, signature.buf,
|
sigc.payload_type = SIGNATURE_PAYLOAD_COMMIT;
|
||||||
signature.len, &sigc);
|
sigc.payload = strbuf_detach(&payload, &sigc.payload_len);
|
||||||
|
status = check_signature(&sigc, signature.buf, signature.len);
|
||||||
if (status && !sigc.output)
|
if (status && !sigc.output)
|
||||||
show_sig_lines(opt, status, "No signature\n");
|
show_sig_lines(opt, status, "No signature\n");
|
||||||
else
|
else
|
||||||
|
@ -583,8 +584,9 @@ static int show_one_mergetag(struct commit *commit,
|
||||||
status = -1;
|
status = -1;
|
||||||
if (parse_signature(extra->value, extra->len, &payload, &signature)) {
|
if (parse_signature(extra->value, extra->len, &payload, &signature)) {
|
||||||
/* could have a good signature */
|
/* could have a good signature */
|
||||||
status = check_signature(payload.buf, payload.len,
|
sigc.payload_type = SIGNATURE_PAYLOAD_TAG;
|
||||||
signature.buf, signature.len, &sigc);
|
sigc.payload = strbuf_detach(&payload, &sigc.payload_len);
|
||||||
|
status = check_signature(&sigc, signature.buf, signature.len);
|
||||||
if (sigc.output)
|
if (sigc.output)
|
||||||
strbuf_addstr(&verify_message, sigc.output);
|
strbuf_addstr(&verify_message, sigc.output);
|
||||||
else
|
else
|
||||||
|
|
62
t/lib-gpg.sh
62
t/lib-gpg.sh
|
@ -90,6 +90,10 @@ test_lazy_prereq RFC1991 '
|
||||||
GPGSSH_KEY_PRIMARY="${GNUPGHOME}/ed25519_ssh_signing_key"
|
GPGSSH_KEY_PRIMARY="${GNUPGHOME}/ed25519_ssh_signing_key"
|
||||||
GPGSSH_KEY_SECONDARY="${GNUPGHOME}/rsa_2048_ssh_signing_key"
|
GPGSSH_KEY_SECONDARY="${GNUPGHOME}/rsa_2048_ssh_signing_key"
|
||||||
GPGSSH_KEY_UNTRUSTED="${GNUPGHOME}/untrusted_ssh_signing_key"
|
GPGSSH_KEY_UNTRUSTED="${GNUPGHOME}/untrusted_ssh_signing_key"
|
||||||
|
GPGSSH_KEY_EXPIRED="${GNUPGHOME}/expired_ssh_signing_key"
|
||||||
|
GPGSSH_KEY_NOTYETVALID="${GNUPGHOME}/notyetvalid_ssh_signing_key"
|
||||||
|
GPGSSH_KEY_TIMEBOXEDVALID="${GNUPGHOME}/timeboxed_valid_ssh_signing_key"
|
||||||
|
GPGSSH_KEY_TIMEBOXEDINVALID="${GNUPGHOME}/timeboxed_invalid_ssh_signing_key"
|
||||||
GPGSSH_KEY_WITH_PASSPHRASE="${GNUPGHOME}/protected_ssh_signing_key"
|
GPGSSH_KEY_WITH_PASSPHRASE="${GNUPGHOME}/protected_ssh_signing_key"
|
||||||
GPGSSH_KEY_PASSPHRASE="super_secret"
|
GPGSSH_KEY_PASSPHRASE="super_secret"
|
||||||
GPGSSH_ALLOWED_SIGNERS="${GNUPGHOME}/ssh.all_valid.allowedSignersFile"
|
GPGSSH_ALLOWED_SIGNERS="${GNUPGHOME}/ssh.all_valid.allowedSignersFile"
|
||||||
|
@ -105,21 +109,61 @@ test_lazy_prereq GPGSSH '
|
||||||
echo $ssh_version | grep -q "find-principals:missing signature file"
|
echo $ssh_version | grep -q "find-principals:missing signature file"
|
||||||
test $? = 0 || exit 1;
|
test $? = 0 || exit 1;
|
||||||
|
|
||||||
# some broken versions of ssh-keygen segfault on find-principals;
|
# Setup some keys and an allowed signers file
|
||||||
# avoid testing with them.
|
|
||||||
ssh-keygen -Y find-principals -f /dev/null -s /dev/null
|
|
||||||
test $? = 139 && exit 1
|
|
||||||
|
|
||||||
mkdir -p "${GNUPGHOME}" &&
|
mkdir -p "${GNUPGHOME}" &&
|
||||||
chmod 0700 "${GNUPGHOME}" &&
|
chmod 0700 "${GNUPGHOME}" &&
|
||||||
(setfacl -k "${GNUPGHOME}" 2>/dev/null || true) &&
|
(setfacl -k "${GNUPGHOME}" 2>/dev/null || true) &&
|
||||||
ssh-keygen -t ed25519 -N "" -C "git ed25519 key" -f "${GPGSSH_KEY_PRIMARY}" >/dev/null &&
|
ssh-keygen -t ed25519 -N "" -C "git ed25519 key" -f "${GPGSSH_KEY_PRIMARY}" >/dev/null &&
|
||||||
echo "\"principal with number 1\" $(cat "${GPGSSH_KEY_PRIMARY}.pub")" >> "${GPGSSH_ALLOWED_SIGNERS}" &&
|
|
||||||
ssh-keygen -t rsa -b 2048 -N "" -C "git rsa2048 key" -f "${GPGSSH_KEY_SECONDARY}" >/dev/null &&
|
ssh-keygen -t rsa -b 2048 -N "" -C "git rsa2048 key" -f "${GPGSSH_KEY_SECONDARY}" >/dev/null &&
|
||||||
echo "\"principal with number 2\" $(cat "${GPGSSH_KEY_SECONDARY}.pub")" >> "${GPGSSH_ALLOWED_SIGNERS}" &&
|
|
||||||
ssh-keygen -t ed25519 -N "${GPGSSH_KEY_PASSPHRASE}" -C "git ed25519 encrypted key" -f "${GPGSSH_KEY_WITH_PASSPHRASE}" >/dev/null &&
|
ssh-keygen -t ed25519 -N "${GPGSSH_KEY_PASSPHRASE}" -C "git ed25519 encrypted key" -f "${GPGSSH_KEY_WITH_PASSPHRASE}" >/dev/null &&
|
||||||
echo "\"principal with number 3\" $(cat "${GPGSSH_KEY_WITH_PASSPHRASE}.pub")" >> "${GPGSSH_ALLOWED_SIGNERS}" &&
|
ssh-keygen -t ed25519 -N "" -C "git ed25519 key" -f "${GPGSSH_KEY_UNTRUSTED}" >/dev/null &&
|
||||||
ssh-keygen -t ed25519 -N "" -f "${GPGSSH_KEY_UNTRUSTED}" >/dev/null
|
|
||||||
|
cat >"${GPGSSH_ALLOWED_SIGNERS}" <<-EOF &&
|
||||||
|
"principal with number 1" $(cat "${GPGSSH_KEY_PRIMARY}.pub")"
|
||||||
|
"principal with number 2" $(cat "${GPGSSH_KEY_SECONDARY}.pub")"
|
||||||
|
"principal with number 3" $(cat "${GPGSSH_KEY_WITH_PASSPHRASE}.pub")"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Verify if at least one key and ssh-keygen works as expected
|
||||||
|
echo "testpayload" |
|
||||||
|
ssh-keygen -Y sign -n "git" -f "${GPGSSH_KEY_PRIMARY}" >gpgssh_prereq.sig &&
|
||||||
|
ssh-keygen -Y find-principals -f "${GPGSSH_ALLOWED_SIGNERS}" -s gpgssh_prereq.sig &&
|
||||||
|
echo "testpayload" |
|
||||||
|
ssh-keygen -Y verify -n "git" -f "${GPGSSH_ALLOWED_SIGNERS}" -I "principal with number 1" -s gpgssh_prereq.sig
|
||||||
|
'
|
||||||
|
|
||||||
|
test_lazy_prereq GPGSSH_VERIFYTIME '
|
||||||
|
# Check if ssh-keygen has a verify-time option by passing an invalid date to it
|
||||||
|
ssh-keygen -Overify-time=INVALID -Y check-novalidate -s doesnotmatter 2>&1 | grep -q -F "Invalid \"verify-time\"" &&
|
||||||
|
|
||||||
|
# Set up keys with key lifetimes
|
||||||
|
ssh-keygen -t ed25519 -N "" -C "timeboxed valid key" -f "${GPGSSH_KEY_TIMEBOXEDVALID}" >/dev/null &&
|
||||||
|
key_valid=$(cat "${GPGSSH_KEY_TIMEBOXEDVALID}.pub") &&
|
||||||
|
ssh-keygen -t ed25519 -N "" -C "timeboxed invalid key" -f "${GPGSSH_KEY_TIMEBOXEDINVALID}" >/dev/null &&
|
||||||
|
key_invalid=$(cat "${GPGSSH_KEY_TIMEBOXEDINVALID}.pub") &&
|
||||||
|
ssh-keygen -t ed25519 -N "" -C "expired key" -f "${GPGSSH_KEY_EXPIRED}" >/dev/null &&
|
||||||
|
key_expired=$(cat "${GPGSSH_KEY_EXPIRED}.pub") &&
|
||||||
|
ssh-keygen -t ed25519 -N "" -C "not yet valid key" -f "${GPGSSH_KEY_NOTYETVALID}" >/dev/null &&
|
||||||
|
key_notyetvalid=$(cat "${GPGSSH_KEY_NOTYETVALID}.pub") &&
|
||||||
|
|
||||||
|
# Timestamps outside of test_tick span
|
||||||
|
ts2005a=20050401000000 ts2005b=200504020000 &&
|
||||||
|
# Timestamps within test_tick span
|
||||||
|
ts2005c=20050407000000 ts2005d=200504100000 &&
|
||||||
|
# Definitely not yet valid / expired timestamps
|
||||||
|
ts2000=20000101000000 ts2999=29990101000000 &&
|
||||||
|
|
||||||
|
cat >>"${GPGSSH_ALLOWED_SIGNERS}" <<-EOF &&
|
||||||
|
"timeboxed valid key" valid-after="$ts2005c",valid-before="$ts2005d" $key_valid"
|
||||||
|
"timeboxed invalid key" valid-after="$ts2005a",valid-before="$ts2005b" $key_invalid"
|
||||||
|
"principal with expired key" valid-before="$ts2000" $key_expired"
|
||||||
|
"principal with not yet valid key" valid-after="$ts2999" $key_notyetvalid"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# and verify ssh-keygen verifies the key lifetime
|
||||||
|
echo "testpayload" |
|
||||||
|
ssh-keygen -Y sign -n "git" -f "${GPGSSH_KEY_EXPIRED}" >gpgssh_verifytime_prereq.sig &&
|
||||||
|
! (ssh-keygen -Y verify -n "git" -f "${GPGSSH_ALLOWED_SIGNERS}" -I "principal with expired key" -s gpgssh_verifytime_prereq.sig)
|
||||||
'
|
'
|
||||||
|
|
||||||
sanitize_pgp() {
|
sanitize_pgp() {
|
||||||
|
|
|
@ -1714,6 +1714,24 @@ test_expect_success GPGSSH 'setup sshkey signed branch' '
|
||||||
git commit -S -m signed_commit
|
git commit -S -m signed_commit
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'create signed commits with keys having defined lifetimes' '
|
||||||
|
test_config gpg.format ssh &&
|
||||||
|
touch file &&
|
||||||
|
git add file &&
|
||||||
|
|
||||||
|
echo expired >file && test_tick && git commit -a -m expired -S"${GPGSSH_KEY_EXPIRED}" &&
|
||||||
|
git tag expired-signed &&
|
||||||
|
|
||||||
|
echo notyetvalid >file && test_tick && git commit -a -m notyetvalid -S"${GPGSSH_KEY_NOTYETVALID}" &&
|
||||||
|
git tag notyetvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedvalid >file && test_tick && git commit -a -m timeboxedvalid -S"${GPGSSH_KEY_TIMEBOXEDVALID}" &&
|
||||||
|
git tag timeboxedvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedinvalid >file && test_tick && git commit -a -m timeboxedinvalid -S"${GPGSSH_KEY_TIMEBOXEDINVALID}" &&
|
||||||
|
git tag timeboxedinvalid-signed
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success GPGSM 'log x509 fingerprint' '
|
test_expect_success GPGSM 'log x509 fingerprint' '
|
||||||
echo "F8BF62E0693D0694816377099909C779FA23FD65 | " >expect &&
|
echo "F8BF62E0693D0694816377099909C779FA23FD65 | " >expect &&
|
||||||
git log -n1 --format="%GF | %GP" signed-x509 >actual &&
|
git log -n1 --format="%GF | %GP" signed-x509 >actual &&
|
||||||
|
@ -1751,6 +1769,31 @@ test_expect_success GPGSSH 'log --graph --show-signature ssh' '
|
||||||
grep "${GOOD_SIGNATURE_TRUSTED}" actual
|
grep "${GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure on expired signature key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git log --graph --show-signature -n1 expired-signed >actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure on not yet valid signature key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git log --graph --show-signature -n1 notyetvalid-signed >actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log show success with commit date and key validity matching' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git log --graph --show-signature -n1 timeboxedvalid-signed >actual &&
|
||||||
|
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
|
||||||
|
! grep "${GPGSSH_BAD_SIGNATURE}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure with commit date outside of key validity' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git log --graph --show-signature -n1 timeboxedinvalid-signed >actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success GPG 'log --graph --show-signature for merged tag' '
|
test_expect_success GPG 'log --graph --show-signature for merged tag' '
|
||||||
test_when_finished "git reset --hard && git checkout main" &&
|
test_when_finished "git reset --hard && git checkout main" &&
|
||||||
git checkout -b plain main &&
|
git checkout -b plain main &&
|
||||||
|
|
|
@ -91,6 +91,26 @@ test_expect_success GPGSSH 'created ssh signed commit and tag' '
|
||||||
git tag -s -u"${GPGSSH_KEY_UNTRUSTED}" -m signed-ssh-tag-msg-untrusted signed-untrusted-ssh-tag left
|
git tag -s -u"${GPGSSH_KEY_UNTRUSTED}" -m signed-ssh-tag-msg-untrusted signed-untrusted-ssh-tag left
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'create signed tags with keys having defined lifetimes' '
|
||||||
|
test_when_finished "test_unconfig commit.gpgsign" &&
|
||||||
|
test_config gpg.format ssh &&
|
||||||
|
git checkout -b signed-expiry-ssh &&
|
||||||
|
touch file &&
|
||||||
|
git add file &&
|
||||||
|
|
||||||
|
echo expired >file && test_tick && git commit -a -m expired -S"${GPGSSH_KEY_EXPIRED}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_EXPIRED}" -m expired-signed expired-signed &&
|
||||||
|
|
||||||
|
echo notyetvalid >file && test_tick && git commit -a -m notyetvalid -S"${GPGSSH_KEY_NOTYETVALID}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_NOTYETVALID}" -m notyetvalid-signed notyetvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedvalid >file && test_tick && git commit -a -m timeboxedvalid -S"${GPGSSH_KEY_TIMEBOXEDVALID}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_TIMEBOXEDVALID}" -m timeboxedvalid-signed timeboxedvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedinvalid >file && test_tick && git commit -a -m timeboxedinvalid -S"${GPGSSH_KEY_TIMEBOXEDINVALID}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_TIMEBOXEDINVALID}" -m timeboxedinvalid-signed timeboxedinvalid-signed
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'message for merging local branch' '
|
test_expect_success 'message for merging local branch' '
|
||||||
echo "Merge branch ${apos}left${apos}" >expected &&
|
echo "Merge branch ${apos}left${apos}" >expected &&
|
||||||
|
|
||||||
|
@ -104,7 +124,7 @@ test_expect_success 'message for merging local branch' '
|
||||||
test_expect_success GPG 'message for merging local tag signed by good key' '
|
test_expect_success GPG 'message for merging local tag signed by good key' '
|
||||||
git checkout main &&
|
git checkout main &&
|
||||||
git fetch . signed-good-tag &&
|
git fetch . signed-good-tag &&
|
||||||
git fmt-merge-msg <.git/FETCH_HEAD >actual 2>&1 &&
|
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
|
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
|
||||||
grep "^# gpg: Signature made" actual &&
|
grep "^# gpg: Signature made" actual &&
|
||||||
grep "^# gpg: Good signature from" actual
|
grep "^# gpg: Good signature from" actual
|
||||||
|
@ -113,7 +133,7 @@ test_expect_success GPG 'message for merging local tag signed by good key' '
|
||||||
test_expect_success GPG 'message for merging local tag signed by unknown key' '
|
test_expect_success GPG 'message for merging local tag signed by unknown key' '
|
||||||
git checkout main &&
|
git checkout main &&
|
||||||
git fetch . signed-good-tag &&
|
git fetch . signed-good-tag &&
|
||||||
GNUPGHOME=. git fmt-merge-msg <.git/FETCH_HEAD >actual 2>&1 &&
|
GNUPGHOME=. git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
|
grep "^Merge tag ${apos}signed-good-tag${apos}" actual &&
|
||||||
grep "^# gpg: Signature made" actual &&
|
grep "^# gpg: Signature made" actual &&
|
||||||
grep -E "^# gpg: Can${apos}t check signature: (public key not found|No public key)" actual
|
grep -E "^# gpg: Can${apos}t check signature: (public key not found|No public key)" actual
|
||||||
|
@ -123,7 +143,8 @@ test_expect_success GPGSSH 'message for merging local tag signed by good ssh key
|
||||||
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
git checkout main &&
|
git checkout main &&
|
||||||
git fetch . signed-good-ssh-tag &&
|
git fetch . signed-good-ssh-tag &&
|
||||||
git fmt-merge-msg <.git/FETCH_HEAD >actual 2>&1 &&
|
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
|
grep "^Merge tag ${apos}signed-good-ssh-tag${apos}" actual &&
|
||||||
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
|
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
|
||||||
! grep "${GPGSSH_BAD_SIGNATURE}" actual
|
! grep "${GPGSSH_BAD_SIGNATURE}" actual
|
||||||
'
|
'
|
||||||
|
@ -132,11 +153,50 @@ test_expect_success GPGSSH 'message for merging local tag signed by unknown ssh
|
||||||
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
git checkout main &&
|
git checkout main &&
|
||||||
git fetch . signed-untrusted-ssh-tag &&
|
git fetch . signed-untrusted-ssh-tag &&
|
||||||
git fmt-merge-msg <.git/FETCH_HEAD >actual 2>&1 &&
|
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
|
grep "^Merge tag ${apos}signed-untrusted-ssh-tag${apos}" actual &&
|
||||||
grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual &&
|
grep "${GPGSSH_GOOD_SIGNATURE_UNTRUSTED}" actual &&
|
||||||
! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
|
! grep "${GPGSSH_BAD_SIGNATURE}" actual &&
|
||||||
grep "${GPGSSH_KEY_NOT_TRUSTED}" actual
|
grep "${GPGSSH_KEY_NOT_TRUSTED}" actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag signed by expired ssh key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git checkout main &&
|
||||||
|
git fetch . expired-signed &&
|
||||||
|
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
|
grep "^Merge tag ${apos}expired-signed${apos}" actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag signed by not yet valid ssh key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git checkout main &&
|
||||||
|
git fetch . notyetvalid-signed &&
|
||||||
|
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
|
grep "^Merge tag ${apos}notyetvalid-signed${apos}" actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag signed by valid timeboxed ssh key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git checkout main &&
|
||||||
|
git fetch . timeboxedvalid-signed &&
|
||||||
|
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
|
grep "^Merge tag ${apos}timeboxedvalid-signed${apos}" actual &&
|
||||||
|
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
|
||||||
|
! grep "${GPGSSH_BAD_SIGNATURE}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'message for merging local tag signed by invalid timeboxed ssh key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git checkout main &&
|
||||||
|
git fetch . timeboxedinvalid-signed &&
|
||||||
|
git fmt-merge-msg <.git/FETCH_HEAD >actual &&
|
||||||
|
grep "^Merge tag ${apos}timeboxedinvalid-signed${apos}" actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'message for merging external branch' '
|
test_expect_success 'message for merging external branch' '
|
||||||
echo "Merge branch ${apos}left${apos} of $(pwd)" >expected &&
|
echo "Merge branch ${apos}left${apos} of $(pwd)" >expected &&
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,23 @@ test_expect_success GPGSSH 'create signed tags ssh' '
|
||||||
git tag -u"${GPGSSH_KEY_UNTRUSTED}" -m eighth eighth-signed-alt
|
git tag -u"${GPGSSH_KEY_UNTRUSTED}" -m eighth eighth-signed-alt
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'create signed tags with keys having defined lifetimes' '
|
||||||
|
test_when_finished "test_unconfig commit.gpgsign" &&
|
||||||
|
test_config gpg.format ssh &&
|
||||||
|
|
||||||
|
echo expired >file && test_tick && git commit -a -m expired -S"${GPGSSH_KEY_EXPIRED}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_EXPIRED}" -m expired-signed expired-signed &&
|
||||||
|
|
||||||
|
echo notyetvalid >file && test_tick && git commit -a -m notyetvalid -S"${GPGSSH_KEY_NOTYETVALID}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_NOTYETVALID}" -m notyetvalid-signed notyetvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedvalid >file && test_tick && git commit -a -m timeboxedvalid -S"${GPGSSH_KEY_TIMEBOXEDVALID}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_TIMEBOXEDVALID}" -m timeboxedvalid-signed timeboxedvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedinvalid >file && test_tick && git commit -a -m timeboxedinvalid -S"${GPGSSH_KEY_TIMEBOXEDINVALID}" &&
|
||||||
|
git tag -s -u "${GPGSSH_KEY_TIMEBOXEDINVALID}" -m timeboxedinvalid-signed timeboxedinvalid-signed
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success GPGSSH 'verify and show ssh signatures' '
|
test_expect_success GPGSSH 'verify and show ssh signatures' '
|
||||||
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
(
|
(
|
||||||
|
@ -80,6 +97,31 @@ test_expect_success GPGSSH 'verify and show ssh signatures' '
|
||||||
)
|
)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag exits failure on expired signature key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
test_must_fail git verify-tag expired-signed 2>actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag exits failure on not yet valid signature key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
test_must_fail git verify-tag notyetvalid-signed 2>actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag succeeds with tag date and key validity matching' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git verify-tag timeboxedvalid-signed 2>actual &&
|
||||||
|
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
|
||||||
|
! grep "${GPGSSH_BAD_SIGNATURE}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-tag failes with tag date outside of key validity' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
test_must_fail git verify-tag timeboxedinvalid-signed 2>actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success GPGSSH 'detect fudged ssh signature' '
|
test_expect_success GPGSSH 'detect fudged ssh signature' '
|
||||||
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
git cat-file tag seventh-signed >raw &&
|
git cat-file tag seventh-signed >raw &&
|
||||||
|
|
|
@ -76,6 +76,23 @@ test_expect_success GPGSSH 'create signed commits' '
|
||||||
git tag twelfth-signed-alt $(cat oid)
|
git tag twelfth-signed-alt $(cat oid)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'create signed commits with keys having defined lifetimes' '
|
||||||
|
test_when_finished "test_unconfig commit.gpgsign" &&
|
||||||
|
test_config gpg.format ssh &&
|
||||||
|
|
||||||
|
echo expired >file && test_tick && git commit -a -m expired -S"${GPGSSH_KEY_EXPIRED}" &&
|
||||||
|
git tag expired-signed &&
|
||||||
|
|
||||||
|
echo notyetvalid >file && test_tick && git commit -a -m notyetvalid -S"${GPGSSH_KEY_NOTYETVALID}" &&
|
||||||
|
git tag notyetvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedvalid >file && test_tick && git commit -a -m timeboxedvalid -S"${GPGSSH_KEY_TIMEBOXEDVALID}" &&
|
||||||
|
git tag timeboxedvalid-signed &&
|
||||||
|
|
||||||
|
echo timeboxedinvalid >file && test_tick && git commit -a -m timeboxedinvalid -S"${GPGSSH_KEY_TIMEBOXEDINVALID}" &&
|
||||||
|
git tag timeboxedinvalid-signed
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success GPGSSH 'verify and show signatures' '
|
test_expect_success GPGSSH 'verify and show signatures' '
|
||||||
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
test_config gpg.mintrustlevel UNDEFINED &&
|
test_config gpg.mintrustlevel UNDEFINED &&
|
||||||
|
@ -122,6 +139,31 @@ test_expect_success GPGSSH 'verify-commit exits failure on untrusted signature'
|
||||||
grep "${GPGSSH_KEY_NOT_TRUSTED}" actual
|
grep "${GPGSSH_KEY_NOT_TRUSTED}" actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit exits failure on expired signature key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
test_must_fail git verify-commit expired-signed 2>actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit exits failure on not yet valid signature key' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
test_must_fail git verify-commit notyetvalid-signed 2>actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit succeeds with commit date and key validity matching' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
git verify-commit timeboxedvalid-signed 2>actual &&
|
||||||
|
grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual &&
|
||||||
|
! grep "${GPGSSH_BAD_SIGNATURE}" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'verify-commit exits failure with commit date outside of key validity' '
|
||||||
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
|
test_must_fail git verify-commit timeboxedinvalid-signed 2>actual &&
|
||||||
|
! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success GPGSSH 'verify-commit exits success with matching minTrustLevel' '
|
test_expect_success GPGSSH 'verify-commit exits success with matching minTrustLevel' '
|
||||||
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
|
||||||
test_config gpg.minTrustLevel fully &&
|
test_config gpg.minTrustLevel fully &&
|
||||||
|
|
5
tag.c
5
tag.c
|
@ -25,8 +25,9 @@ static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
|
||||||
return error("no signature found");
|
return error("no signature found");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = check_signature(payload.buf, payload.len, signature.buf,
|
sigc.payload_type = SIGNATURE_PAYLOAD_TAG;
|
||||||
signature.len, &sigc);
|
sigc.payload = strbuf_detach(&payload, &sigc.payload_len);
|
||||||
|
ret = check_signature(&sigc, signature.buf, signature.len);
|
||||||
|
|
||||||
if (!(flags & GPG_VERIFY_OMIT_STATUS))
|
if (!(flags & GPG_VERIFY_OMIT_STATUS))
|
||||||
print_signature_buffer(&sigc, flags);
|
print_signature_buffer(&sigc, flags);
|
||||||
|
|
Loading…
Reference in New Issue