-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathstore.c
153 lines (138 loc) · 4 KB
/
store.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <endian.h>
#include <spawn.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "sha3.h"
#include "crypto.h"
#include "chacha20.h"
#include "binhex.h"
#include "store.h"
int emit_file_record(FILE *f, const char *name, size_t len)
{
struct tar_header {
char name[100];
char mode[8], uid[8], gid[8], size[12], mtime[12], cksum[8], type, linked[100];
char magic[6], ver[2];
char user[32], group[32];
char major[8], minor[8];
char prefix[155];
char pad[12];
//char pad[512-257];
} h = {
.mode = "0000644", .uid = "0000000", .gid = "0000000", .mtime = "0000000",
.cksum = " ", .type = '0',
.magic = "ustar", .ver = "00",
};
snprintf(h.name, sizeof h.name, "%s", name);
snprintf(h.size, sizeof h.size, "%.7zo", len); // FIXME - check that it fits
int sum = 0;
for (int i=0; i<sizeof h; i++)
sum += ((unsigned char *)&h)[i];
snprintf(h.cksum, sizeof h.cksum, "%.6o", sum);
fwrite(&h, 1, sizeof h, f);
return 0;
}
static int emit_pad(size_t unpadded_size, FILE *f)
{
static const char zeros[511];
size_t cnt = -unpadded_size & 511;
if (fwrite(zeros, 1, cnt, f) != cnt) return -1;
return 0;
}
void gen_blob_name(char *name, const unsigned char *hash)
{
size_t j = sizeof BLOBNAME_PREFIX - 1;
memcpy(name, BLOBNAME_PREFIX, j);
bin2hex(name+j, hash, HASHLEN);
memcpy(name+j-4, name+j, 3);
}
int emit_new_blob(unsigned char *label, FILE *f, unsigned char *data, size_t len, struct crypto_context *cc)
{
uint64_t nonce = get_nonce(cc);
chacha20_buf(data, len, cc->ephemeral_key, nonce);
sha3_ctx_t h;
sha3_init(&h, HASHLEN);
sha3_update(&h, cc->ephemeral_public, sizeof cc->ephemeral_public);
nonce = htole64(nonce);
sha3_update(&h, &nonce, sizeof nonce);
sha3_update(&h, data, len);
sha3_final(label, &h);
char name[BLOBNAME_SIZE];
gen_blob_name(name, label);
size_t blob_size = len + sizeof cc->ephemeral_public + sizeof nonce;
emit_file_record(f, name, blob_size);
fwrite(cc->ephemeral_public, 1, sizeof cc->ephemeral_public, f);
fwrite(&(uint64_t){htole64(nonce)}, 1, sizeof nonce, f);
fwrite(data, 1, len, f);
emit_pad(blob_size, f);
return 0;
}
int emit_clear_file(FILE *f, const char *name, const void *data, size_t len)
{
if (emit_file_record(f, name, len) ||
fwrite(data, 1, len, f) != len ||
emit_pad(len, f))
return -1;
return 0;
}
int emit_signature_file(FILE *out, const char *name, const void *data, size_t dlen, const char *signing_cmd)
{
pid_t pid = -1;
extern char **environ;
int pout[2]={-1,-1}, pin[2]={-1,-1};
posix_spawn_file_actions_t fa;
int fa_live = 0;
int ret = -1;
FILE *f = 0;
char *sigdata = 0;
size_t sigsize = 0;
ssize_t siglen;
if (pipe2(pout, O_CLOEXEC) || pipe2(pin, O_CLOEXEC))
goto fail;
if (posix_spawn_file_actions_init(&fa))
goto fail;
fa_live = 1;
if (posix_spawn_file_actions_adddup2(&fa, pout[0], 0) ||
posix_spawn_file_actions_adddup2(&fa, pin[1], 1) ||
posix_spawn_file_actions_addclose(&fa, pout[1]) ||
posix_spawn_file_actions_addclose(&fa, pin[0]) ||
posix_spawnp(&pid, "sh", &fa, 0, (char *[])
{ "sh", "-c", (char *)signing_cmd, 0 },
environ))
{
goto fail;
}
close(pout[0]); pout[0] = -1;
close(pin[1]); pin[1] = -1;
f = fdopen(pout[1], "wb");
if (!f) goto fail;
pout[1] = -1;
if (fwrite(data, 1, dlen, f) != dlen || fflush(f))
goto fail;
fclose(f); f = 0;
f = fdopen(pin[0], "rb");
if (!f) goto fail;
pin[0] = -1;
siglen = getdelim(&sigdata, &sigsize, 0, f);
if (siglen < 0) goto fail;
fclose(f); f = 0;
if (emit_file_record(out, name, siglen)) goto fail;
if (fwrite(sigdata, 1, siglen, out) != siglen) goto fail;
if (emit_pad(siglen, out) || fflush(out)) goto fail;
fail:
if (fa_live) posix_spawn_file_actions_destroy(&fa);
if (pout[0]>=0) close(pout[0]);
if (pout[1]>=0) close(pout[1]);
if (pin[0]>=0) close(pin[0]);
if (pin[1]>=0) close(pin[1]);
int status = 0;
if (pid>=1) waitpid(pid, &status, 0);
if (status) ret = -1;
free(sigdata);
return ret;
}