48
static int sent_capabilities;
49
static int shallow_update;
50
static const char *alt_shallow_file;
51
-static int accept_push_cert = 1;
51
static struct strbuf push_cert = STRBUF_INIT;
52
static unsigned char push_cert_sha1[20];
53
static struct signature_check sigcheck;
54
+static const char *push_cert_nonce;
55
+static const char *cert_nonce_seed;
56
+
57
+static const char *NONCE_UNSOLICITED = "UNSOLICITED";
58
+static const char *NONCE_BAD = "BAD";
59
+static const char *NONCE_MISSING = "MISSING";
60
+static const char *NONCE_OK = "OK";
61
+static const char *nonce_status;
62
63
static enum deny_action parse_deny_action(const char *var, const char *value)
64
{
142
return 0;
143
}
144
138
- if (strcmp(var, "receive.acceptpushcert") == 0) {
139
- accept_push_cert = git_config_bool(var, value);
140
- return 0;
141
- }
145
+ if (strcmp(var, "receive.certnonceseed") == 0)
146
+ return git_config_string(&cert_nonce_seed, var, value);
147
148
return git_default_config(var, value, cb);
149
}
162
"report-status delete-refs side-band-64k quiet");
163
if (prefer_ofs_delta)
164
strbuf_addstr(&cap, " ofs-delta");
160
- if (accept_push_cert)
161
- strbuf_addstr(&cap, " push-cert");
165
+ if (push_cert_nonce)
166
+ strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
167
strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
168
packet_write(1, "%s %s%c%s\n",
169
sha1_to_hex(sha1), path, 0, cap.buf);
276
return 0;
277
}
278
279
+#define HMAC_BLOCK_SIZE 64
280
+
281
+static void hmac_sha1(unsigned char out[20],
282
+ const char *key_in, size_t key_len,
283
+ const char *text, size_t text_len)
284
+{
285
+ unsigned char key[HMAC_BLOCK_SIZE];
286
+ unsigned char k_ipad[HMAC_BLOCK_SIZE];
287
+ unsigned char k_opad[HMAC_BLOCK_SIZE];
288
+ int i;
289
+ git_SHA_CTX ctx;
290
+
291
+ /* RFC 2104 2. (1) */
292
+ memset(key, '\0', HMAC_BLOCK_SIZE);
293
+ if (HMAC_BLOCK_SIZE < key_len) {
294
+ git_SHA1_Init(&ctx);
295
+ git_SHA1_Update(&ctx, key_in, key_len);
296
+ git_SHA1_Final(key, &ctx);
297
+ } else {
298
+ memcpy(key, key_in, key_len);
299
+ }
300
+
301
+ /* RFC 2104 2. (2) & (5) */
302
+ for (i = 0; i < sizeof(key); i++) {
303
+ k_ipad[i] = key[i] ^ 0x36;
304
+ k_opad[i] = key[i] ^ 0x5c;
305
+ }
306
+
307
+ /* RFC 2104 2. (3) & (4) */
308
+ git_SHA1_Init(&ctx);
309
+ git_SHA1_Update(&ctx, k_ipad, sizeof(k_ipad));
310
+ git_SHA1_Update(&ctx, text, text_len);
311
+ git_SHA1_Final(out, &ctx);
312
+
313
+ /* RFC 2104 2. (6) & (7) */
314
+ git_SHA1_Init(&ctx);
315
+ git_SHA1_Update(&ctx, k_opad, sizeof(k_opad));
316
+ git_SHA1_Update(&ctx, out, sizeof(out));
317
+ git_SHA1_Final(out, &ctx);
318
+}
319
+
320
+static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)
321
+{
322
+ struct strbuf buf = STRBUF_INIT;
323
+ unsigned char sha1[20];
324
+
325
+ strbuf_addf(&buf, "%s:%lu", path, stamp);
326
+ hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;
327
+ strbuf_release(&buf);
328
+
329
+ /* RFC 2104 5. HMAC-SHA1-80 */
330
+ strbuf_addf(&buf, "%lu-%.*s", stamp, 20, sha1_to_hex(sha1));
331
+ return strbuf_detach(&buf, NULL);
332
+}
333
+
334
+/*
335
+ * NEEDSWORK: reuse find_commit_header() from jk/commit-author-parsing
336
+ * after dropping "_commit" from its name and possibly moving it out
337
+ * of commit.c
338
+ */
339
+static char *find_header(const char *msg, size_t len, const char *key)
340
+{
341
+ int key_len = strlen(key);
342
+ const char *line = msg;
343
+
344
+ while (line && line < msg + len) {
345
+ const char *eol = strchrnul(line, '\n');
346
+
347
+ if ((msg + len <= eol) || line == eol)
348
+ return NULL;
349
+ if (line + key_len < eol &&
350
+ !memcmp(line, key, key_len) && line[key_len] == ' ') {
351
+ int offset = key_len + 1;
352
+ return xmemdupz(line + offset, (eol - line) - offset);
353
+ }
354
+ line = *eol ? eol + 1 : NULL;
355
+ }
356
+ return NULL;
357
+}
358
+
359
+static const char *check_nonce(const char *buf, size_t len)
360
+{
361
+ char *nonce = find_header(buf, len, "nonce");
362
+ const char *retval = NONCE_BAD;
363
+
364
+ if (!nonce) {
365
+ retval = NONCE_MISSING;
366
+ goto leave;
367
+ } else if (!push_cert_nonce) {
368
+ retval = NONCE_UNSOLICITED;
369
+ goto leave;
370
+ } else if (!strcmp(push_cert_nonce, nonce)) {
371
+ retval = NONCE_OK;
372
+ goto leave;
373
+ }
374
+
375
+ /* returned nonce MUST match what we gave out earlier */
376
+ retval = NONCE_BAD;
377
+
378
+leave:
379
+ free(nonce);
380
+ return retval;
381
+}
382
+
383
static void prepare_push_cert_sha1(struct child_process *proc)
384
{
385
static int already_done;
414
415
strbuf_release(&gpg_output);
416
strbuf_release(&gpg_status);
417
+ nonce_status = check_nonce(push_cert.buf, bogs);
418
}
419
if (!is_null_sha1(push_cert_sha1)) {
420
argv_array_pushf(&env, "GIT_PUSH_CERT=%s", sha1_to_hex(push_cert_sha1));
423
argv_array_pushf(&env, "GIT_PUSH_CERT_KEY=%s",
424
sigcheck.key ? sigcheck.key : "");
425
argv_array_pushf(&env, "GIT_PUSH_CERT_STATUS=%c", sigcheck.result);
316
-
426
+ if (push_cert_nonce) {
427
+ argv_array_pushf(&env, "GIT_PUSH_CERT_NONCE=%s", push_cert_nonce);
428
+ argv_array_pushf(&env, "GIT_PUSH_CERT_NONCE_STATUS=%s", nonce_status);
429
+ }
430
proc->env = env.argv;
431
}
432
}
1409
die("'%s' does not appear to be a git repository", dir);
1410
1411
git_config(receive_pack_config, NULL);
1412
+ if (cert_nonce_seed)
1413
+ push_cert_nonce = prepare_push_cert_nonce(dir, time(NULL));
1414
1415
if (0 <= transfer_unpack_limit)
1416
unpack_limit = transfer_unpack_limit;
1455
packet_flush(1);
1456
sha1_array_clear(&shallow);
1457
sha1_array_clear(&ref);
1458
+ free((void *)push_cert_nonce);
1459
return 0;
1460
}