From: Ibrahim El Rhezzali <ibrahim...@pm.me>

7e3e6c9e4 Added new signing interface API

Adding files for the new signing interface and also support drivers for the two 
existing GPG and GPGSM X.509 tools

Signed-off-by: Ibrahim El <ibrahim...@pm.me>
---
 Makefile               |   3 +
 signing-interface.c    | 487 +++++++++++++++++++++++++++++++++++++++++++++++++
 signing-interface.h    | 151 +++++++++++++++
 signing-tool-openpgp.c | 409 +++++++++++++++++++++++++++++++++++++++++
 signing-tool-x509.c    | 383 ++++++++++++++++++++++++++++++++++++++
 signing-tool.h         |  35 ++++
 6 files changed, 1468 insertions(+)
 create mode 100644 signing-interface.c
 create mode 100644 signing-interface.h
 create mode 100644 signing-tool-openpgp.c
 create mode 100644 signing-tool-x509.c
 create mode 100644 signing-tool.h

diff --git a/Makefile b/Makefile
index f58bf14c7..244540e8d 100644
--- a/Makefile
+++ b/Makefile
@@ -978,6 +978,9 @@ LIB_OBJS += sha1-name.o
 LIB_OBJS += shallow.o
 LIB_OBJS += sideband.o
 LIB_OBJS += sigchain.o
+LIB_OBJS += signing-interface.o
+LIB_OBJS += signing-tool-openpgp.o
+LIB_OBJS += signing-tool-x509.o
 LIB_OBJS += split-index.o
 LIB_OBJS += strbuf.o
 LIB_OBJS += streaming.o
diff --git a/signing-interface.c b/signing-interface.c
new file mode 100644
index 000000000..c744ef499
--- /dev/null
+++ b/signing-interface.c
@@ -0,0 +1,487 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include "cache.h"
+#include "config.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "signing-interface.h"
+#include "signing-tool.h"
+#include "sigchain.h"
+#include "tempfile.h"
+
+extern const struct signing_tool openpgp_tool;
+extern const struct signing_tool x509_tool;
+
+static const struct signing_tool *signing_tools[SIGNATURE_TYPE_COUNT] = {
+       &openpgp_tool,
+       &x509_tool,
+};
+
+enum signature_type default_type = SIGNATURE_TYPE_DEFAULT;
+static const char* unknown_signature_type = "unknown signature type";
+static char* default_signing_key = NULL;
+
+static void add_signature(struct signatures *sigs, struct signature *sig) {
+       if (!sigs || !sig)
+               return;
+       ALLOC_GROW(sigs->sigs, sigs->nsigs + 1, sigs->alloc);
+       sigs->sigs[sigs->nsigs++] = sig;
+}
+
+void signatures_clear(struct signatures *sigs)
+{
+       size_t i;
+       struct signature *psig;
+
+       if (!sigs) return;
+       
+       for (i = 0; i < sigs->nsigs; i++) {
+               psig = sigs->sigs[i];
+               strbuf_release(&(psig->sig));
+               strbuf_release(&(psig->output));
+               strbuf_release(&(psig->status));
+               FREE_AND_NULL(psig->signer);
+               FREE_AND_NULL(psig->key);
+               FREE_AND_NULL(psig->fingerprint);
+               FREE_AND_NULL(psig->key);
+               FREE_AND_NULL(psig);
+       }
+       FREE_AND_NULL(sigs->sigs);
+       sigs->nsigs = 0;
+       sigs->alloc = 0;
+}
+
+void signature_clear(struct signature *sigc)
+{
+       FREE_AND_NULL(sigc->sig.buf);
+       FREE_AND_NULL(sigc->output.buf);
+       FREE_AND_NULL(sigc->status.buf);
+       FREE_AND_NULL(sigc->signer);
+       FREE_AND_NULL(sigc->key);
+       FREE_AND_NULL(sigc->fingerprint);
+       FREE_AND_NULL(sigc->primary_key_fingerprint);
+}
+
+int sign_payload(const char *payload, size_t size, struct signatures *sigs,
+               enum signature_type st, const char *signing_key)
+{
+       const struct signing_tool *tool;
+       struct signature *psig = xmalloc(sizeof(struct signature));
+       int ret;
+
+       fflush(stdout);
+
+       if (!sigs)
+               return error("invalid signatures passed to sign function");
+
+       if (!VALID_SIGNATURE_TYPE(st))
+               return error("unsupported signature type: %d", st);
+
+       tool = signing_tools[st];
+
+       if (!tool || !tool->sign)
+               BUG("signing tool %s undefined", signature_type_name(st));
+
+       ret = tool->sign(payload, size, &psig, signing_key);
+       if (!ret)
+               add_signature(sigs, psig);
+       else
+
+               return error("signing operation failed");
+
+       return 0;
+}
+
+int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char 
*signing_key)
+{
+       struct signatures sigs = SIGNATURES_INIT;
+       enum signature_type st = default_type;
+
+       int ret = sign_payload(buffer->buf, buffer->len, &sigs, st, 
signing_key);
+
+       if (!ret)
+       {
+               strbuf_addstr(signature, sigs.sigs[0]->sig.buf);
+       }
+
+       return ret;
+}
+
+size_t parse_signatures(const char *payload, size_t size, 
+               struct signatures *sigs)
+{
+       enum signature_type st;
+       size_t first;
+       size_t begin = 0;
+       const struct signing_tool *tool;
+       struct signature *psig = NULL;
+
+       first = size;
+       for (st = SIGNATURE_TYPE_FIRST; st < SIGNATURE_TYPE_LAST; st++) {
+               tool = signing_tools[st];
+
+               if (!tool || !tool->parse)
+                       BUG("signing tool %s undefined", 
signature_type_name(st));
+
+               begin = tool->parse(payload, size, &psig);
+               if (begin < size) {
+                       if (sigs)
+                               add_signature(sigs, psig);
+                       else
+                               FREE_AND_NULL(psig);
+
+                       first = begin;
+                       continue;
+               }
+       }
+
+       return first;
+}
+
+size_t parse_signature(const char *buf, size_t size)
+{
+       size_t match;
+       struct signatures sigs = SIGNATURES_INIT;
+
+       if ( !buf || !size )
+               return size;
+
+       match = parse_signatures(buf, size, &sigs);
+
+       return match;
+}
+
+int verify_buffer_signatures(const char *payload, size_t size,
+               struct signatures *sigs)
+{
+       int ret = 0;
+       size_t i;
+       const struct signing_tool *tool;
+       struct signature *psig;
+
+       if (!sigs)
+               error("invalid signatures passed to verify function");
+
+       for (i = 0; i < sigs->nsigs; i++) {
+               psig = sigs->sigs[i];
+               tool = signing_tools[psig->st];
+
+               if (!tool || !tool->verify)
+                       BUG("signing tool %s undefined", 
signature_type_name(psig->st));
+
+               ret |= tool->verify(payload, size, psig);
+       }
+
+       return ret;
+}
+
+int verify_signed_buffer(const char *payload, size_t payload_size,
+                        const char *signature, size_t signature_size,
+                        struct strbuf *output, struct strbuf *status)
+{
+       int ret;
+       enum signature_type st;
+       struct signature sig = SIGNATURE_INIT;
+       struct signatures sigs = SIGNATURES_INIT;
+
+       if ( !payload || !signature )
+               return error("invalid payload or signature sent !");
+
+       strbuf_addstr(&(sig.sig), signature);
+       add_signature(&sigs, &sig);
+
+       ret = verify_buffer_signatures(payload, payload_size, &sigs);
+
+       /*  Some how gpg.format is not sometimes applied, temporary fix to loop 
and STs */
+       if (ret)
+       {
+               for (st = SIGNATURE_TYPE_FIRST; st < SIGNATURE_TYPE_LAST; st++)
+               {
+                       sig.st = st;
+                       ret = verify_buffer_signatures(payload, payload_size, 
&sigs);
+                       if (!ret || sig.result != '0')
+                               break;
+               }
+       }
+
+       if (output)
+               strbuf_addstr(output, sig.output.buf);
+       if (status)
+               strbuf_addstr(status, sig.status.buf);
+
+       return ret;
+}
+
+int check_signature(const char *payload, size_t plen, const char *signature,
+       size_t slen, struct signature *sigc)
+{
+       int status;
+       enum signature_type st;
+       struct signatures sigs = SIGNATURES_INIT;
+       struct signature sig = SIGNATURE_INIT;
+       
+       if (!payload || !signature || !sigc)
+               BUG("invalid payload or signature sent !");
+
+       strbuf_addstr(&(sig.sig), signature);
+       sig.result = 'N';
+       sig.st = default_type;
+
+       add_signature(&sigs, &sig);
+
+       status = verify_buffer_signatures(payload, plen, &sigs);
+
+       /*  Some how gpg.format is not sometimes applied, temporary fix to loop 
and STs */
+       if (status)
+       {
+               for (st = SIGNATURE_TYPE_FIRST; st < SIGNATURE_TYPE_LAST; st++)
+               {
+                       sig.st = st;
+                       status = verify_buffer_signatures(payload, plen, &sigs);
+                       if (!status || sig.result != 'N')
+                               break;
+               }
+       }
+       status |= sig.result != 'G' && sig.result != 'U';
+
+       if (sig.signer && !sigc->signer)
+               sigc->signer = xstrdup(sig.signer);
+       if (sig.key && !sigc->key)
+               sigc->key = xstrdup(sig.key);
+       if (sig.fingerprint && !sigc->fingerprint)
+               sigc->fingerprint = xstrdup(sig.fingerprint);
+       if (sig.primary_key_fingerprint && !sigc->primary_key_fingerprint)
+               sigc->primary_key_fingerprint = 
xstrdup(sig.primary_key_fingerprint);   
+
+       sigc->st = sig.st;
+       sigc->result = sig.result;
+       
+       strbuf_addstr(&(sigc->sig), payload);
+       strbuf_addstr(&(sigc->output), sig.output.buf);
+       strbuf_addstr(&(sigc->status), sig.status.buf);
+
+       return !!status;
+}
+
+size_t strbuf_append_signatures(struct strbuf *buf, const struct signatures 
*sigs)
+{
+       size_t i;
+       struct signature *psig;
+
+       if (!buf)
+               BUG("invalid buffer passed to signature append function");
+
+       if (!sigs)
+               return 0;
+
+       for (i = 0; i < sigs->nsigs; i++) {
+               psig = sigs->sigs[i];
+               strbuf_addbuf(buf, &(psig->sig));
+       }
+
+       return sigs->nsigs;
+}
+
+void print_signatures(const struct signatures *sigs, unsigned flags)
+{
+       size_t i;
+       const struct signing_tool *tool;
+       const struct signature *psig;
+
+       if (!sigs)
+               error("invalid signatures passed to verify function");
+
+       for (i = 0; i < sigs->nsigs; i++) {
+               psig = sigs->sigs[i];
+               tool = signing_tools[psig->st];
+
+               if (!tool || !tool->print)
+                       BUG("signing tool %s undefined", 
signature_type_name(psig->st));
+
+               tool->print(psig, flags);
+       }
+}
+
+void print_signature_buffer(const struct signature *sigc, unsigned flags)
+{
+       const struct signing_tool *tool;
+
+       if (!sigc)
+               error("invalid signatures passed to verify function");
+
+       tool = signing_tools[default_type];
+
+       if (!tool || !tool->print)
+               BUG("signing tool %s undefined", signature_type_name(sigc->st));
+
+       tool->print(sigc, flags);
+}
+
+enum signature_type signature_type_by_name(const char *name)
+{
+       enum signature_type st;
+
+       if (!name)
+               return default_type;
+
+       for (st = SIGNATURE_TYPE_FIRST; st < SIGNATURE_TYPE_LAST; st++)
+               if (!strcmp(signing_tools[st]->name, name))
+                       return st;
+
+       return error("unknown signature type: %s", name);
+}
+
+const char *signature_type_name(enum signature_type st)
+{
+       if (!VALID_SIGNATURE_TYPE(st))
+               return unknown_signature_type;
+
+       return signing_tools[st]->name;
+}
+
+int git_signing_config(const char *var, const char *value, void *cb)
+{
+       int ret = 0;
+       char *t1, *t2, *t3, *buf;
+       enum signature_type st;
+       const struct signing_tool *tool;
+
+       /* user.signingkey is a deprecated alias for 
signing.<signing.default>.key */
+       if (!strcmp(var, "user.signingkey")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               
+               set_signing_key(value, default_type);
+
+               return 0;
+       }
+
+       /* gpg.format is a deprecated alias for signing.default */
+       if (!strcmp(var, "gpg.format") || !strcmp(var, "signing.default")) {
+               if (!value)
+                       return config_error_nonbool(var);
+
+               if (!VALID_SIGNATURE_TYPE((st = signature_type_by_name(value))))
+                       return config_error_nonbool(var);
+
+               set_signature_type(st);
+
+               return 0;
+       }
+
+       /* gpg.program is a deprecated alias for signing.openpgp.program */
+       if (!strcmp(var, "gpg.program") || !strcmp(var, 
"signing.openpgp.program")) {
+               ret = signing_tools[OPENPGP_SIGNATURE]->config(
+                               "program", value, cb);
+
+               return ret;
+       }
+
+       /* gpg.x509.program is a deprecated alias for signing.x509.program */
+       if (!strcmp(var, "gpg.x509.program") || !strcmp(var, 
"signing.x509.program")) {
+               ret = signing_tools[X509_SIGNATURE]->config(
+                               "program", value, cb);
+
+               return ret;
+       }
+
+       buf = xstrdup(var);
+       t1 = strtok(buf, ".");
+       t2 = strtok(NULL, ".");
+       t3 = strtok(NULL, ".");
+
+       /* gpg.<format>.* is a deprecated alias for signing.<format>.* */
+       if (!strcmp(t1, "gpg") || !strcmp(t1, "signing")) {
+               if (!VALID_SIGNATURE_TYPE((st = signature_type_by_name(t2)))) {
+                       free(buf);
+                       return error("unsupported variable: %s", var);
+               }
+
+               tool = signing_tools[st];
+               if (!tool || !tool->config) {
+                       free(buf);
+                       BUG("signing tool %s undefined", 
signature_type_name(tool->st));
+               }
+
+               ret = tool->config(t3, value, cb);
+       }
+
+       free(buf);
+       return ret;
+}
+
+void set_signing_key(const char *key, enum signature_type st)
+{
+       /*
+        * Make sure we track the latest default signing key so that if the
+        * default signing format changes after this, we can make sure the
+        * default signing tool knows the key to use.
+        */
+       free(default_signing_key);
+       default_signing_key = xstrdup(key);
+
+       if (!VALID_SIGNATURE_TYPE(st))
+               signing_tools[default_type]->set_key(key);
+       else
+               signing_tools[st]->set_key(key);
+}
+
+const char *get_signing_key(enum signature_type st)
+{
+       if (!VALID_SIGNATURE_TYPE(st))
+               return signing_tools[default_type]->get_key();
+
+       return signing_tools[default_type]->get_key();
+}
+
+void set_signing_program(const char *signing_program, enum signature_type st)
+{
+       /*
+        * Make sure we track the latest default signing program so that if the
+        * default signing format changes after this, we can make sure the
+        * default signing tool knows the program to use.
+        */
+
+       if (!VALID_SIGNATURE_TYPE(st))
+               signing_tools[default_type]->set_program(signing_program);
+       else
+               signing_tools[st]->set_program(signing_program);
+}
+
+const char *get_signing_program(enum signature_type st)
+{
+       const char *signing_program = NULL;
+
+       if (!VALID_SIGNATURE_TYPE(st)) {
+               signing_program = signing_tools[default_type]->get_program();
+
+               return signing_program;
+       }
+
+       signing_program = signing_tools[st]->get_program();
+
+       return signing_program;
+}
+
+void set_signature_type(enum signature_type st)
+{
+       if (!VALID_SIGNATURE_TYPE(st))
+               return;
+
+       default_type = st;
+
+       /* 
+        * If the signing key has been set, then make sure the new default
+        * signing tool knows about it. this fixes the order of operations
+        * error of parsing the default signing key and default signing
+        * format in arbitrary order.
+        */
+       if (default_signing_key) {
+               set_signing_key(default_signing_key, default_type);
+       }
+}
+
+enum signature_type get_signature_type(void)
+{
+       return default_type;
+}
\ No newline at end of file
diff --git a/signing-interface.h b/signing-interface.h
new file mode 100644
index 000000000..b55edbdb8
--- /dev/null
+++ b/signing-interface.h
@@ -0,0 +1,151 @@
+#ifndef SIGNING_INTERFACE_H
+#define SIGNING_INTERFACE_H
+
+struct strbuf;
+
+#define OUTPUT_VERBOSE         1
+#define OUTPUT_RAW                     2
+#define OUTPUT_OMIT_STATUS     4
+
+enum signature_type {
+       OPENPGP_SIGNATURE,
+       X509_SIGNATURE,
+
+       SIGNATURE_TYPE_LAST,
+       SIGNATURE_TYPE_FIRST = OPENPGP_SIGNATURE,
+       SIGNATURE_TYPE_COUNT = SIGNATURE_TYPE_LAST - SIGNATURE_TYPE_FIRST,
+       SIGNATURE_TYPE_DEFAULT = OPENPGP_SIGNATURE,
+       SIGNATURE_TYPE_UNKNOWN = -1
+};
+enum signature_type default_type;
+
+#define VALID_SIGNATURE_TYPE(x) \
+       ((x >= SIGNATURE_TYPE_FIRST) && (x < SIGNATURE_TYPE_LAST))
+
+struct signature {
+       struct strbuf sig;
+       struct strbuf output;
+       struct strbuf status;
+       enum signature_type st;
+
+       /*
+        * possible "result":
+        * 0 (not checked)
+        * N (checked but no further result)
+        * U (untrusted good)
+        * G (good)
+        * B (bad)
+        */
+       char result;
+       char *signer;
+       char *key;
+       char *fingerprint;
+       char *primary_key_fingerprint;
+};
+
+struct signatures {
+       size_t nsigs;
+       size_t alloc;
+       struct signature **sigs;
+};
+
+#define SIGNATURES_INIT  { .nsigs = 0, .alloc = 0, .sigs = NULL }
+#define SIGNATURE_INIT  { .sig = STRBUF_INIT, .output = STRBUF_INIT, .status = 
STRBUF_INIT, .st = OPENPGP_SIGNATURE, .result = '0', .signer = NULL, .key = 
NULL }
+
+void signatures_clear(struct signatures *sigs);
+void signature_clear(struct signature *sig);
+
+/*
+ * Create a detached signature for the contents of "payload" and append
+ * it to the list of signatures in "sigs". The signature type determines which
+ * type of signature to create and the optional "signing_key" specifies
+ * the key. If no signing key is specified the default key from the
+ * config will be used. If no default is found, then an error is
+ * returned. If the signing operation fails an error is returned.
+ */
+int sign_payload(const char *payload, size_t size, struct signatures *sigs,
+               enum signature_type st, const char *signing_key);
+
+/*
+ * Bridge function to be called by the git code for buffer signature
+ */
+int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char 
*signing_key);
+
+/* 
+ * Look at the signed content (e.g. a signed tag object), whose payload
+ * is followed by one or more detached signatures. Return the offset of
+ * the first signature, or the size of the buf when there are no 
+ * signatures. If a valid signatures struct is passed in, the signatures 
+ * will be parsed and copied into its array of sigs.
+ */
+size_t parse_signatures(const char *payload, size_t size,
+               struct signatures *sigs);
+
+/*
+ * Bridge function to be called by the git code for parsing signatures in a 
buffer
+ */
+size_t parse_signature(const char *buf, size_t size);
+
+/*
+ * Run the signature verification tools to see if the payload matches
+ * the detached signatures. The output and status of the of the checks
+ * is recorded in the signatures struct. The caller must use
+ * parse_signatures or sign_buffer to initialize the signatures struct
+ * before calling this function.
+ */
+int verify_signed_buffer(const char *payload, size_t payload_size,
+                        const char *signature, size_t signature_size,
+                        struct strbuf *output, struct strbuf *status);
+
+/*
+ * Verify multiple signatures in a single buffer
+ */
+int verify_buffer_signatures(const char *payload, size_t size,
+               struct signatures *sigs);
+
+/*
+ * Bridge function to be called by the git code to verify a signed payload
+ */
+int check_signature(const char *payload, size_t plen, const char *signature,
+       size_t slen, struct signature *sigc);
+
+/*
+ * Prints the results of either signing or verifying the payload in the
+ * signatures struct. If the OUTPUT_VERBOSE flag is specified, then the
+ * payload is printed to stdout. If the OUTPUT_RAW flag is specified, 
+ * the raw status output from the signing tool is printed to stderr, 
+ * otherwise, the nice results from the tool is printed to stderr.
+ */
+void print_signatures(const struct signatures *sigs, unsigned flags);
+
+/*
+ * Bridge function to be called by the git code to print a signature
+ */
+void print_signature_buffer(const struct signature *sigc, unsigned flags);
+
+/*
+ * Appends each of the detached signatures to the end of the strbuf
+ * passed in. Returns the number of signatures appended to the buffer.
+ */
+size_t strbuf_append_signatures(struct strbuf *buf, const struct signatures 
*sigs);
+
+/*
+ * Translate the name of the signature tool into the enumerated value
+ * for the signature type.
+ */
+enum signature_type signature_type_by_name(const char *name);
+const char *signature_type_name(enum signature_type st);
+
+/*
+ * Config related functions
+ */
+int git_signing_config(const char *var, const char *value, void *cb);
+void set_signing_key(const char *key, enum signature_type st);
+const char *get_signing_key(enum signature_type st);
+void set_signing_program(const char *program, enum signature_type st);
+const char *get_signing_program(enum signature_type st);
+void set_signature_type(enum signature_type st);
+enum signature_type get_signature_type(void);
+
+#endif
+
diff --git a/signing-tool-openpgp.c b/signing-tool-openpgp.c
new file mode 100644
index 000000000..93b63b36d
--- /dev/null
+++ b/signing-tool-openpgp.c
@@ -0,0 +1,409 @@
+#include "cache.h"
+#include "config.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "signing-interface.h"
+#include "signing-tool.h"
+#include "sigchain.h"
+#include "tempfile.h"
+
+static int openpgp_sign(const char *payload, size_t size,
+               struct signature **sig, const char *key);
+static size_t openpgp_parse(const char *payload, size_t size,
+               struct signature **sig);
+static int openpgp_verify(const char *payload, size_t size,
+               struct signature *sig);
+static void openpgp_print(const struct signature *sig, unsigned flags);
+static int openpgp_config(const char *, const char *, void *);
+static void openpgp_set_key(const char *);
+static const char *openpgp_get_key(void);
+static void openpgp_set_program(const char *);
+static const char *openpgp_get_program(void);
+
+const struct signing_tool openpgp_tool = {
+       .st = OPENPGP_SIGNATURE,
+       .name = "openpgp",
+       .sign = &openpgp_sign,
+       .parse = &openpgp_parse,
+       .verify = &openpgp_verify,
+       .print = &openpgp_print,
+       .config = &openpgp_config,
+       .set_key = &openpgp_set_key,
+       .get_key = &openpgp_get_key,
+       .set_program = &openpgp_set_program,
+       .get_program = &openpgp_get_program
+};
+
+static const char *program = "gpg";
+static const char *signing_key = NULL;
+static const char *keyring = NULL;
+static int no_default_keyring = 0;
+struct regex_pattern {
+       const char * begin;
+       const char * end;
+};
+static struct regex_pattern patterns[2] = {
+       { "^-----BEGIN PGP SIGNATURE-----\n", "-----END PGP SIGNATURE-----\n" },
+       { "^-----BEGIN PGP MESSAGE-----\n", "-----END PGP MESSAGE-----\n" }
+};
+
+static int openpgp_sign(const char *payload, size_t size,
+               struct signature **sig, const char *key)
+{
+       struct child_process gpg = CHILD_PROCESS_INIT;
+       struct signature *psig;
+       struct strbuf *psignature, *pstatus;
+       int ret;
+       size_t i, j;
+       const char *skey = (!key || !*key) ? signing_key : key;
+
+       /*
+        * Create the signature.
+        */
+       if (sig) {
+               psig = *sig;
+               strbuf_init(&(psig->sig), 0);
+               strbuf_init(&(psig->output), 0);
+               strbuf_init(&(psig->status), 0);
+               psig->st = OPENPGP_SIGNATURE;
+               psig->result = 0;
+               psig->signer = NULL;
+               psig->key = NULL;
+               psignature = &(psig->sig);
+               pstatus = &(psig->status);
+       } else {
+               psignature = NULL;
+               pstatus = NULL;
+       }
+
+       argv_array_pushl(&gpg.args,
+                       program,
+                       "--status-fd=2",
+                       "-bsau", skey,
+                       NULL);
+
+       /*
+        * When the username signingkey is bad, program could be terminated
+        * because gpg exits without reading and then write gets SIGPIPE.
+        */
+       sigchain_push(SIGPIPE, SIG_IGN);
+       ret = pipe_command(&gpg, payload, size,
+                       psignature, 1024, pstatus, 0);
+       sigchain_pop(SIGPIPE);
+
+       if (!sig)
+               return !!ret;
+
+       /* Check for success status from gpg */
+       ret |= !strstr(pstatus->buf, "\n[GNUPG:] SIG_CREATED ");
+
+       if (ret)
+               return error(_("gpg failed to sign the data"));
+
+       /* Mark the signature as good */
+       psig->result = 'G';
+
+       /* Strip CR from the line endings, in case we are on Windows. */
+       for (i = j = 0; i < psig->sig.len; i++)
+               if (psig->sig.buf[i] != '\r') {
+                       if (i != j)
+                               psig->sig.buf[j] = psig->sig.buf[i];
+                       j++;
+               }
+       strbuf_setlen(&(psig->sig), j);
+
+       /* Store the key we used */
+       psig->key = xstrdup(skey);
+
+       return 0;
+}
+
+/*
+ * To get all OpenPGP signatures in a payload, repeatedly call this function
+ * giving it the remainder of the payload as the payload pointer. The return
+ * value is the index of the first char of the signature in the payload. If
+ * no signature is found, size is returned.
+ */
+static size_t openpgp_parse(const char *payload, size_t size,
+               struct signature **sig)
+{
+       int i, ret;
+       regex_t rbegin;
+       regex_t rend;
+       regmatch_t bmatch;
+       regmatch_t ematch;
+       size_t begin, end;
+       struct signature *psig;
+       static char errbuf[1024];
+
+       if (size == 0)
+               return size;
+
+       /*
+        * Figure out if any OpenPGP signatures are in the payload and which
+        * begin pattern matches the first signature in the payload.
+        */
+       for (i = 0; i < ARRAY_SIZE(patterns); i++) {
+               if ((ret = regcomp(&rbegin, patterns[i].begin, 
REG_EXTENDED|REG_NEWLINE))) {
+                       regerror(ret, &rbegin, errbuf, 1024);
+                       BUG("Failed to compile regex: %s\n", errbuf);
+
+                       return size;
+               }
+               if ((ret = regcomp(&rend, patterns[i].end, 
REG_EXTENDED|REG_NEWLINE))) {
+                       regerror(ret, &rend, errbuf, 1024);
+                       BUG("Failed to compile regex: %s\n", errbuf);
+
+                       return size;
+               }
+
+               begin = end = 0;
+               if (regexec(&rbegin, payload, 1, &bmatch, 0) ||
+                       regexec(&rend, payload, 1, &ematch, 0)) {
+                       begin = size;
+                       continue;
+               }
+               begin = bmatch.rm_so;
+               end = ematch.rm_eo;
+
+               break;
+       }
+       if (begin == size)
+               goto next;
+
+       /*
+        * Create the signature.
+        */
+       if (sig) {
+               psig = *sig;
+               psig = xmalloc(sizeof(struct signature));
+               strbuf_init(&(psig->sig), end - begin);
+               strbuf_add(&(psig->sig), payload + begin, end - begin);
+               strbuf_init(&(psig->output), 0);
+               strbuf_init(&(psig->status), 0);
+               psig->st = OPENPGP_SIGNATURE;
+               psig->result = 0;
+               psig->signer = NULL;
+               psig->key = NULL;
+       }
+       next:
+               regfree(&rbegin);
+               regfree(&rend);
+
+       return begin;
+}
+
+/* An exclusive status -- only one of them can appear in output */
+#define GPG_STATUS_EXCLUSIVE   (1<<0)
+/* The status includes key identifier */
+#define GPG_STATUS_KEYID       (1<<1)
+/* The status includes user identifier */
+#define GPG_STATUS_UID         (1<<2)
+/* The status includes key fingerprints */
+#define GPG_STATUS_FINGERPRINT (1<<3)
+
+/* Short-hand for standard exclusive *SIG status with keyid & UID */
+#define GPG_STATUS_STDSIG      
(GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID)
+
+static struct {
+       char result;
+       const char *check;
+       unsigned int flags;
+} sigcheck_gpg_status[] = {
+       { 'G', "GOODSIG ", GPG_STATUS_STDSIG },
+       { 'B', "BADSIG ", GPG_STATUS_STDSIG },
+       { 'U', "TRUST_NEVER", 0 },
+       { 'U', "TRUST_UNDEFINED", 0 },
+       { 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID },
+       { 'X', "EXPSIG ", GPG_STATUS_STDSIG },
+       { 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG },
+       { 'R', "REVKEYSIG ", GPG_STATUS_STDSIG },
+       { 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT },
+};
+
+static void parse_output(struct signature *sigc)
+{
+       const char *buf = sigc->status.buf;
+       const char *line, *next;
+       int i, j;
+       int seen_exclusive_status = 0;
+
+       /* Iterate over all lines */
+       for (line = buf; *line; line = strchrnul(line+1, '\n')) {
+               while (*line == '\n')
+                       line++;
+               /* Skip lines that don't start with GNUPG status */
+               if (!skip_prefix(line, "[GNUPG:] ", &line))
+                       continue;
+
+               /* Iterate over all search strings */
+               for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
+                       if (skip_prefix(line, sigcheck_gpg_status[i].check, 
&line)) {
+                               if (sigcheck_gpg_status[i].flags & 
GPG_STATUS_EXCLUSIVE) {
+                                       if (seen_exclusive_status++)
+                                               goto found_duplicate_status;
+                               }
+
+                               if (sigcheck_gpg_status[i].result)
+                                       sigc->result = 
sigcheck_gpg_status[i].result;
+                               /* Do we have key information? */
+                               if (sigcheck_gpg_status[i].flags & 
GPG_STATUS_KEYID) {
+                                       next = strchrnul(line, ' ');
+                                       free(sigc->key);
+                                       sigc->key = xmemdupz(line, next - line);
+                                       /* Do we have signer information? */
+                                       if (*next && 
(sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) {
+                                               line = next + 1;
+                                               next = strchrnul(line, '\n');
+                                               free(sigc->signer);
+                                               sigc->signer = xmemdupz(line, 
next - line);
+                                       }
+                               }
+                               /* Do we have fingerprint? */
+                               if (sigcheck_gpg_status[i].flags & 
GPG_STATUS_FINGERPRINT) {
+                                       next = strchrnul(line, ' ');
+                                       free(sigc->fingerprint);
+                                       sigc->fingerprint = xmemdupz(line, next 
- line);
+
+                                       /* Skip interim fields */
+                                       for (j = 9; j > 0; j--) {
+                                               if (!*next)
+                                                       break;
+                                               line = next + 1;
+                                               next = strchrnul(line, ' ');
+                                       }
+
+                                       next = strchrnul(line, '\n');
+                                       free(sigc->primary_key_fingerprint);
+                                       sigc->primary_key_fingerprint = 
xmemdupz(line, next - line);
+                               }
+
+                               break;
+                       }
+               }
+       }
+       return;
+
+found_duplicate_status:
+       /*
+        * GOODSIG, BADSIG etc. can occur only once for each signature.
+        * Therefore, if we had more than one then we're dealing with multiple
+        * signatures.  We don't support them currently, and they're rather
+        * hard to create, so something is likely fishy and we should reject
+        * them altogether.
+        */
+       sigc->result = 'E';
+       /* Clear partial data to avoid confusion */
+       FREE_AND_NULL(sigc->primary_key_fingerprint);
+       FREE_AND_NULL(sigc->fingerprint);
+       FREE_AND_NULL(sigc->signer);
+       FREE_AND_NULL(sigc->key);
+}
+
+static int openpgp_verify(const char *payload, size_t size,
+               struct signature *sig)
+{
+       struct child_process gpg = CHILD_PROCESS_INIT;
+       struct tempfile *temp;
+       int ret;
+
+       temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
+       if (!temp)
+               return error_errno(_("could not create temporary file"));
+       if (write_in_full(temp->fd, sig->sig.buf, sig->sig.len) < 0 ||
+           close_tempfile_gently(temp) < 0) {
+               error_errno(_("failed writing detached signature to '%s'"),
+                               temp->filename.buf);
+               delete_tempfile(&temp);
+               return -1;
+       }
+
+       argv_array_push(&gpg.args, program);
+       if (keyring)
+               argv_array_pushl(&gpg.args, "--keyring", keyring, NULL);
+       if (no_default_keyring)
+               argv_array_push(&gpg.args, "--no-default-keyring");
+       argv_array_pushl(&gpg.args,
+                       "--keyid-format=long",
+                       "--status-fd=1",
+                       "--verify", temp->filename.buf, "-",
+                       NULL);
+
+       strbuf_reset(&(sig->status));
+       strbuf_reset(&(sig->output));
+
+       sigchain_push(SIGPIPE, SIG_IGN);
+       ret = pipe_command(&gpg, payload, size,
+                       &(sig->status), 0, &(sig->output), 0);
+       sigchain_pop(SIGPIPE);
+
+       delete_tempfile(&temp);
+
+       ret |= !strstr(sig->status.buf, "\n[GNUPG:] GOODSIG ");
+
+       if (ret && !sig->output.len)
+               return !!ret;
+
+       parse_output(sig);
+
+       ret |= sig->result != 'G' && sig->result != 'U';
+
+       return !!ret;
+}
+
+static void openpgp_print(const struct signature *sig, unsigned flags)
+{
+       const char *output = flags & OUTPUT_RAW ?
+               sig->status.buf : sig->output.buf;
+
+       if (flags & OUTPUT_VERBOSE && sig->sig.buf)
+               fputs(sig->sig.buf, stdout);
+
+       if (output)
+               fputs(output, stderr);
+}
+
+static int openpgp_config(const char *var, const char *value, void *cb)
+{
+       if (!strcmp(var, "program"))
+               return git_config_string(&program, var, value);
+
+       if (!strcmp(var, "key"))
+               return git_config_string(&signing_key, var, value);
+
+       if (!strcmp(var, "keyring"))
+               return git_config_string(&keyring, var, value);
+
+       if (!strcmp(var, "nodefaultkeyring")) {
+               no_default_keyring = git_config_bool(var, value);
+               return 0;
+       }
+       return 0;
+}
+
+static void openpgp_set_key(const char *key)
+{
+       free((void*)signing_key);
+       signing_key = xstrdup(key);
+}
+
+static const char *openpgp_get_key(void)
+{
+       if (signing_key)
+               return signing_key;
+       return git_committer_info(IDENT_STRICT|IDENT_NO_DATE);
+}
+
+static void openpgp_set_program(const char *signing_program)
+{
+       free((void*)program);
+       program = xstrdup(signing_program);
+}
+
+
+static const char *openpgp_get_program(void)
+{
+       if (program)
+               return program;
+       return git_committer_info(IDENT_STRICT|IDENT_NO_DATE);
+}
\ No newline at end of file
diff --git a/signing-tool-x509.c b/signing-tool-x509.c
new file mode 100644
index 000000000..b7de56924
--- /dev/null
+++ b/signing-tool-x509.c
@@ -0,0 +1,383 @@
+#include "cache.h"
+#include "config.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "signing-interface.h"
+#include "signing-tool.h"
+#include "sigchain.h"
+#include "tempfile.h"
+
+static int x509_sign(const char *payload, size_t size,
+               struct signature **sig, const char *key);
+static size_t x509_parse(const char *payload, size_t size,
+               struct signature **sig);
+static int x509_verify(const char *payload, size_t size,
+               struct signature *sig);
+static void x509_print(const struct signature *sig, unsigned flags);
+static int x509_config(const char *, const char *, void *);
+static void x509_set_key(const char *);
+static const char *x509_get_key(void);
+static void x509_set_program(const char *);
+static const char *x509_get_program(void);
+
+const struct signing_tool x509_tool = {
+       .st = X509_SIGNATURE,
+       .name = "x509",
+       .sign = &x509_sign,
+       .parse = &x509_parse,
+       .verify = &x509_verify,
+       .print = &x509_print,
+       .config = &x509_config,
+       .set_key = &x509_set_key,
+       .get_key = &x509_get_key,
+       .set_program = &x509_set_program,
+       .get_program = &x509_get_program
+};
+
+static const char *program = "gpgsm";
+static const char *signing_key = NULL;
+struct regex_pattern {
+       const char * begin;
+       const char * end;
+};
+static struct regex_pattern pattern = {
+       "^-----BEGIN SIGNED MESSAGE-----\n",
+       "^-----END SIGNED MESSAGE-----\n"
+};
+
+static int x509_sign(const char *payload, size_t size,
+               struct signature **sig, const char *key)
+{
+       struct child_process gpgsm = CHILD_PROCESS_INIT;
+       struct signature *psig;
+       struct strbuf *psignature, *pstatus;
+       int ret;
+       size_t i, j;
+       const char *skey = (!key || !*key) ? signing_key : key;
+
+       /*
+        * Create the signature.
+        */
+       if (sig) {
+               psig = *sig;
+               strbuf_init(&(psig->sig), 0);
+               strbuf_init(&(psig->output), 0);
+               strbuf_init(&(psig->status), 0);
+               psig->st = X509_SIGNATURE;
+               psig->result = 0;
+               psig->signer = NULL;
+               psig->key = NULL;
+               psignature = &(psig->sig);
+               pstatus = &(psig->status);
+       } else {
+               psignature = NULL;
+               pstatus = NULL;
+       }
+
+       argv_array_pushl(&gpgsm.args,
+                       program,
+                       "--status-fd=2",
+                       "-bsau", skey,
+                       NULL);
+
+       /*
+        * When the username signingkey is bad, program could be terminated
+        * because gpgsm exits without reading and then write gets SIGPIPE.
+        */
+       sigchain_push(SIGPIPE, SIG_IGN);
+       ret = pipe_command(&gpgsm, payload, size,
+                       psignature, 1024, pstatus, 0);
+       sigchain_pop(SIGPIPE);
+
+       if (!sig)
+               return !!ret;
+
+       ret |= !strstr(pstatus->buf, "\n[GNUPG:] SIG_CREATED ");
+       if (ret)
+               return error(_("gpgsm failed to sign the data"));
+
+       /* Mark the signature as good. */
+       psig->result = 'G';
+
+       /* Strip CR from the line endings, in case we are on Windows. */
+       for (i = j = 0; i < psig->sig.len; i++)
+               if (psig->sig.buf[i] != '\r') {
+                       if (i != j)
+                               psig->sig.buf[j] = psig->sig.buf[i];
+                       j++;
+               }
+       strbuf_setlen(&(psig->sig), j);
+
+       /* Store the key we used */
+       psig->key = xstrdup(skey);
+
+       return 0;
+}
+
+static size_t x509_parse(const char *payload, size_t size,
+               struct signature **sig)
+{
+       int ret;
+       regex_t rbegin;
+       regex_t rend;
+       regmatch_t bmatch;
+       regmatch_t ematch;
+       size_t begin, end;
+       struct signature *psig;
+       static char errbuf[1024];
+
+       if (size == 0)
+               return size;
+
+       /*
+        * Find the first x509 signature in the payload and copy it into the
+        * signature struct.
+        */
+       if ((ret = regcomp(&rbegin, pattern.begin, REG_EXTENDED|REG_NEWLINE))) {
+               regerror(ret, &rbegin, errbuf, 1024);
+               BUG("Failed to compile regex: %s\n", errbuf);
+
+               return size;
+       }
+       if ((ret = regcomp(&rend, pattern.end, REG_EXTENDED|REG_NEWLINE))) {
+               regerror(ret, &rend, errbuf, 1024);
+               BUG("Failed to compile regex: %s\n", errbuf);
+
+               return size;
+       }
+
+       begin = end = 0;
+       if (regexec(&rbegin, payload, 1, &bmatch, 0) ||
+               regexec(&rend, payload, 1, &ematch, 0)) {
+               begin = size;
+       }
+       if (begin == size)
+               goto next;
+
+       begin = bmatch.rm_so;
+       end = ematch.rm_eo;
+
+       /*
+        * Create the signature.
+        */
+       if (sig) {
+               psig = *sig;
+               psig = xmalloc(sizeof(struct signature));
+               strbuf_init(&(psig->sig), end - begin);
+               strbuf_add(&(psig->sig), payload + begin, end - begin);
+               strbuf_init(&(psig->output), 0);
+               strbuf_init(&(psig->status), 0);
+               psig->st = X509_SIGNATURE;
+               psig->result = 0;
+               psig->signer = NULL;
+               psig->key = NULL;
+       }
+
+       next:
+               regfree(&rbegin);
+               regfree(&rend);
+
+       return begin;
+}
+
+/* An exclusive status -- only one of them can appear in output */
+#define GPG_STATUS_EXCLUSIVE   (1<<0)
+/* The status includes key identifier */
+#define GPG_STATUS_KEYID       (1<<1)
+/* The status includes user identifier */
+#define GPG_STATUS_UID         (1<<2)
+/* The status includes key fingerprints */
+#define GPG_STATUS_FINGERPRINT (1<<3)
+
+/* Short-hand for standard exclusive *SIG status with keyid & UID */
+#define GPG_STATUS_STDSIG      
(GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID)
+
+static struct {
+       char result;
+       const char *check;
+       unsigned int flags;
+} sigcheck_gpg_status[] = {
+       { 'G', "GOODSIG ", GPG_STATUS_STDSIG },
+       { 'B', "BADSIG ", GPG_STATUS_STDSIG },
+       { 'U', "TRUST_NEVER", 0 },
+       { 'U', "TRUST_UNDEFINED", 0 },
+       { 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID },
+       { 'X', "EXPSIG ", GPG_STATUS_STDSIG },
+       { 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG },
+       { 'R', "REVKEYSIG ", GPG_STATUS_STDSIG },
+       { 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT },
+};
+
+static void parse_output(struct signature *sigc)
+{
+       const char *buf = sigc->status.buf;
+       const char *line, *next;
+       int i, j;
+       int seen_exclusive_status = 0;
+
+       /* Iterate over all lines */
+       for (line = buf; *line; line = strchrnul(line+1, '\n')) {
+               while (*line == '\n')
+                       line++;
+               /* Skip lines that don't start with GNUPG status */
+               if (!skip_prefix(line, "[GNUPG:] ", &line))
+                       continue;
+
+               /* Iterate over all search strings */
+               for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
+                       if (skip_prefix(line, sigcheck_gpg_status[i].check, 
&line)) {
+                               if (sigcheck_gpg_status[i].flags & 
GPG_STATUS_EXCLUSIVE) {
+                                       if (seen_exclusive_status++)
+                                               goto found_duplicate_status;
+                               }
+
+                               if (sigcheck_gpg_status[i].result)
+                                       sigc->result = 
sigcheck_gpg_status[i].result;
+                               /* Do we have key information? */
+                               if (sigcheck_gpg_status[i].flags & 
GPG_STATUS_KEYID) {
+                                       next = strchrnul(line, ' ');
+                                       free(sigc->key);
+                                       sigc->key = xmemdupz(line, next - line);
+                                       /* Do we have signer information? */
+                                       if (*next && 
(sigcheck_gpg_status[i].flags & GPG_STATUS_UID)) {
+                                               line = next + 1;
+                                               next = strchrnul(line, '\n');
+                                               free(sigc->signer);
+                                               sigc->signer = xmemdupz(line, 
next - line);
+                                       }
+                               }
+                               /* Do we have fingerprint? */
+                               if (sigcheck_gpg_status[i].flags & 
GPG_STATUS_FINGERPRINT) {
+                                       next = strchrnul(line, ' ');
+                                       free(sigc->fingerprint);
+                                       sigc->fingerprint = xmemdupz(line, next 
- line);
+
+                                       /* Skip interim fields */
+                                       for (j = 9; j > 0; j--) {
+                                               if (!*next)
+                                                       break;
+                                               line = next + 1;
+                                               next = strchrnul(line, ' ');
+                                       }
+
+                                       next = strchrnul(line, '\n');
+                                       free(sigc->primary_key_fingerprint);
+                                       sigc->primary_key_fingerprint = 
xmemdupz(line, next - line);
+                               }
+
+                               break;
+                       }
+               }
+       }
+       return;
+
+found_duplicate_status:
+       /*
+        * GOODSIG, BADSIG etc. can occur only once for each signature.
+        * Therefore, if we had more than one then we're dealing with multiple
+        * signatures.  We don't support them currently, and they're rather
+        * hard to create, so something is likely fishy and we should reject
+        * them altogether.
+        */
+       sigc->result = 'E';
+       /* Clear partial data to avoid confusion */
+       FREE_AND_NULL(sigc->primary_key_fingerprint);
+       FREE_AND_NULL(sigc->fingerprint);
+       FREE_AND_NULL(sigc->signer);
+       FREE_AND_NULL(sigc->key);
+}
+
+static int x509_verify(const char *payload, size_t size,
+               struct signature *sig)
+{
+       struct child_process gpgsm = CHILD_PROCESS_INIT;
+       struct tempfile *temp;
+       int ret;
+
+       temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
+       if (!temp)
+               return error_errno(_("could not create temporary file"));
+       if (write_in_full(temp->fd, sig->sig.buf, sig->sig.len) < 0 ||
+           close_tempfile_gently(temp) < 0) {
+               error_errno(_("failed writing detached signature to '%s'"),
+                               temp->filename.buf);
+               delete_tempfile(&temp);
+               return -1;
+       }
+
+       argv_array_push(&gpgsm.args, program);
+       argv_array_pushl(&gpgsm.args,
+                       "--status-fd=1",
+                       "--verify", temp->filename.buf, "-",
+                       NULL);
+
+       strbuf_reset(&(sig->status));
+       strbuf_reset(&(sig->output));
+
+       sigchain_push(SIGPIPE, SIG_IGN);
+       ret = pipe_command(&gpgsm, payload, size,
+                       &(sig->status), 0, &(sig->output), 0);
+       sigchain_pop(SIGPIPE);
+
+       delete_tempfile(&temp);
+
+       ret |= !strstr(sig->status.buf, "\n[GNUPG:] GOODSIG ");
+
+       if (ret && !sig->output.len)
+               return !!ret;
+
+       parse_output(sig);
+
+       ret |= sig->result != 'G' && sig->result != 'U';
+
+       return !!ret;
+}
+
+static void x509_print(const struct signature *sig, unsigned flags)
+{
+       const char *output = flags & OUTPUT_RAW ?
+               sig->status.buf : sig->output.buf;
+
+       if (flags & OUTPUT_VERBOSE && sig->sig.buf)
+               fputs(sig->sig.buf, stdout);
+
+       if (output)
+               fputs(output, stderr);
+}
+
+static int x509_config(const char *var, const char *value, void *cb)
+{
+       if (!strcmp(var, "program"))
+               return git_config_string(&program, var, value);
+
+       if (!strcmp(var, "key"))
+               return git_config_string(&signing_key, var, value);
+
+       return 0;
+}
+
+static void x509_set_key(const char *key)
+{
+       free((void*)signing_key);
+       signing_key = xstrdup(key);
+}
+
+static const char *x509_get_key(void)
+{
+       if (signing_key)
+               return signing_key;
+       return git_committer_info(IDENT_STRICT|IDENT_NO_DATE);
+}
+
+static void x509_set_program(const char *signing_program)
+{
+       free((void*)program);
+       program = xstrdup(signing_program);
+}
+
+static const char *x509_get_program(void)
+{
+       if (program)
+               return program;
+       return git_committer_info(IDENT_STRICT|IDENT_NO_DATE);
+}
\ No newline at end of file
diff --git a/signing-tool.h b/signing-tool.h
new file mode 100644
index 000000000..ee7ccc7a5
--- /dev/null
+++ b/signing-tool.h
@@ -0,0 +1,35 @@
+#ifndef SIGNING_TOOL_H
+#define SIGNING_TOOL_H
+
+struct strbuf;
+struct signature;
+
+typedef int (*sign_fn)(const char *payload, size_t size,
+       struct signature **sig, const char *key);
+typedef size_t (*parse_fn)(const char *payload, size_t size,
+       struct signature **sig);
+typedef int (*verify_fn)(const char *payload, size_t size,
+       struct signature *sig);
+typedef void (*print_fn)(const struct signature *sig, unsigned flags);
+typedef int (*config_fn)(const char *var, const char *value, void *cb);
+typedef void (*set_key_fn)(const char *key);
+typedef const char *(*get_key_fn)(void);
+typedef void (*set_program_fn)(const char *signing_program);
+typedef const char *(*get_program_fn)(void);
+
+struct signing_tool {
+       const enum signature_type st;
+       const char* name;
+       sign_fn sign;
+       parse_fn parse;
+       verify_fn verify;
+       print_fn print;
+       config_fn config;
+       set_key_fn set_key;
+       get_key_fn get_key;
+       set_program_fn set_program;
+       get_program_fn get_program;
+};
+
+#endif
+
-- 
2.11.0


Reply via email to