]>
Commit | Line | Data |
---|---|---|
2f47eae2 JH |
1 | #include "cache.h" |
2 | #include "run-command.h" | |
3 | #include "strbuf.h" | |
4 | #include "gpg-interface.h" | |
5 | #include "sigchain.h" | |
6 | ||
7 | static char *configured_signing_key; | |
0c5e70f0 | 8 | static const char *gpg_program = "gpg"; |
2f47eae2 | 9 | |
01e57b5d MG |
10 | void signature_check_clear(struct signature_check *sigc) |
11 | { | |
71c214c8 | 12 | free(sigc->payload); |
01e57b5d MG |
13 | free(sigc->gpg_output); |
14 | free(sigc->gpg_status); | |
15 | free(sigc->signer); | |
16 | free(sigc->key); | |
71c214c8 | 17 | sigc->payload = NULL; |
01e57b5d MG |
18 | sigc->gpg_output = NULL; |
19 | sigc->gpg_status = NULL; | |
20 | sigc->signer = NULL; | |
21 | sigc->key = NULL; | |
22 | } | |
23 | ||
2f47eae2 JH |
24 | void set_signing_key(const char *key) |
25 | { | |
26 | free(configured_signing_key); | |
27 | configured_signing_key = xstrdup(key); | |
28 | } | |
29 | ||
30 | int git_gpg_config(const char *var, const char *value, void *cb) | |
31 | { | |
32 | if (!strcmp(var, "user.signingkey")) { | |
0c5e70f0 JH |
33 | set_signing_key(value); |
34 | } | |
35 | if (!strcmp(var, "gpg.program")) { | |
2f47eae2 JH |
36 | if (!value) |
37 | return config_error_nonbool(var); | |
0c5e70f0 | 38 | gpg_program = xstrdup(value); |
2f47eae2 JH |
39 | } |
40 | return 0; | |
41 | } | |
42 | ||
43 | const char *get_signing_key(void) | |
44 | { | |
45 | if (configured_signing_key) | |
46 | return configured_signing_key; | |
f9bc573f | 47 | return git_committer_info(IDENT_STRICT|IDENT_NO_DATE); |
2f47eae2 JH |
48 | } |
49 | ||
50 | /* | |
51 | * Create a detached signature for the contents of "buffer" and append | |
52 | * it after "signature"; "buffer" and "signature" can be the same | |
53 | * strbuf instance, which would cause the detached signature appended | |
54 | * at the end. | |
55 | */ | |
56 | int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key) | |
57 | { | |
58 | struct child_process gpg; | |
59 | const char *args[4]; | |
60 | ssize_t len; | |
61 | size_t i, j, bottom; | |
62 | ||
63 | memset(&gpg, 0, sizeof(gpg)); | |
64 | gpg.argv = args; | |
65 | gpg.in = -1; | |
66 | gpg.out = -1; | |
0c5e70f0 | 67 | args[0] = gpg_program; |
2f47eae2 JH |
68 | args[1] = "-bsau"; |
69 | args[2] = signing_key; | |
70 | args[3] = NULL; | |
71 | ||
72 | if (start_command(&gpg)) | |
73 | return error(_("could not run gpg.")); | |
74 | ||
75 | /* | |
76 | * When the username signingkey is bad, program could be terminated | |
77 | * because gpg exits without reading and then write gets SIGPIPE. | |
78 | */ | |
79 | sigchain_push(SIGPIPE, SIG_IGN); | |
80 | ||
81 | if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) { | |
82 | close(gpg.in); | |
83 | close(gpg.out); | |
84 | finish_command(&gpg); | |
85 | return error(_("gpg did not accept the data")); | |
86 | } | |
87 | close(gpg.in); | |
88 | ||
89 | bottom = signature->len; | |
90 | len = strbuf_read(signature, gpg.out, 1024); | |
91 | close(gpg.out); | |
92 | ||
93 | sigchain_pop(SIGPIPE); | |
94 | ||
95 | if (finish_command(&gpg) || !len || len < 0) | |
96 | return error(_("gpg failed to sign the data")); | |
97 | ||
98 | /* Strip CR from the line endings, in case we are on Windows. */ | |
99 | for (i = j = bottom; i < signature->len; i++) | |
100 | if (signature->buf[i] != '\r') { | |
101 | if (i != j) | |
102 | signature->buf[j] = signature->buf[i]; | |
103 | j++; | |
104 | } | |
105 | strbuf_setlen(signature, j); | |
106 | ||
107 | return 0; | |
108 | } | |
109 | ||
110 | /* | |
111 | * Run "gpg" to see if the payload matches the detached signature. | |
e3f55e07 | 112 | * gpg_output, when set, receives the diagnostic output from GPG. |
b60b7566 | 113 | * gpg_status, when set, receives the status output from GPG. |
2f47eae2 JH |
114 | */ |
115 | int verify_signed_buffer(const char *payload, size_t payload_size, | |
116 | const char *signature, size_t signature_size, | |
9cc4ac8f | 117 | struct strbuf *gpg_output, struct strbuf *gpg_status) |
2f47eae2 JH |
118 | { |
119 | struct child_process gpg; | |
b60b7566 | 120 | const char *args_gpg[] = {NULL, "--status-fd=1", "--verify", "FILE", "-", NULL}; |
2f47eae2 JH |
121 | char path[PATH_MAX]; |
122 | int fd, ret; | |
b60b7566 | 123 | struct strbuf buf = STRBUF_INIT; |
9cc4ac8f | 124 | struct strbuf *pbuf = &buf; |
2f47eae2 | 125 | |
0c5e70f0 | 126 | args_gpg[0] = gpg_program; |
2f47eae2 JH |
127 | fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX"); |
128 | if (fd < 0) | |
4c9a4182 | 129 | return error(_("could not create temporary file '%s': %s"), |
2f47eae2 JH |
130 | path, strerror(errno)); |
131 | if (write_in_full(fd, signature, signature_size) < 0) | |
4c9a4182 | 132 | return error(_("failed writing detached signature to '%s': %s"), |
2f47eae2 JH |
133 | path, strerror(errno)); |
134 | close(fd); | |
135 | ||
136 | memset(&gpg, 0, sizeof(gpg)); | |
137 | gpg.argv = args_gpg; | |
138 | gpg.in = -1; | |
b60b7566 | 139 | gpg.out = -1; |
2f47eae2 JH |
140 | if (gpg_output) |
141 | gpg.err = -1; | |
b60b7566 | 142 | args_gpg[3] = path; |
2f47eae2 JH |
143 | if (start_command(&gpg)) { |
144 | unlink(path); | |
4c9a4182 | 145 | return error(_("could not run gpg.")); |
2f47eae2 JH |
146 | } |
147 | ||
148 | write_in_full(gpg.in, payload, payload_size); | |
149 | close(gpg.in); | |
150 | ||
7dac3f83 | 151 | if (gpg_output) { |
2f47eae2 | 152 | strbuf_read(gpg_output, gpg.err, 0); |
7dac3f83 SB |
153 | close(gpg.err); |
154 | } | |
9cc4ac8f MG |
155 | if (gpg_status) |
156 | pbuf = gpg_status; | |
157 | strbuf_read(pbuf, gpg.out, 0); | |
b60b7566 MG |
158 | close(gpg.out); |
159 | ||
2f47eae2 JH |
160 | ret = finish_command(&gpg); |
161 | ||
162 | unlink_or_warn(path); | |
163 | ||
9cc4ac8f MG |
164 | ret |= !strstr(pbuf->buf, "\n[GNUPG:] GOODSIG "); |
165 | strbuf_release(&buf); /* no matter it was used or not */ | |
b60b7566 | 166 | |
2f47eae2 JH |
167 | return ret; |
168 | } |