/
doc.go
202 lines (131 loc) · 7.78 KB
/
doc.go
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
Package ssot implements a single source of truth (SSOT) with DNS TXT records.
Signed head specification
Signed heads have the following fields:
- VERSION (1-byte), the signed head version (only from V2 onwards).
- PUBKEY (32-byte), the Ed25519 public key of SSOT head signer.
- PUBKEY_ROTATE (32-byte), Ed25519 pubkey to rotate to, set to 0 if unused.
- VALID_FROM (8-byte), the signed head is valid from the given Unix time.
- VALID_TO (8-byte), the signed head is valid to the given Unix time.
- COUNTER (8-byte), strictly increasing signature counter.
- HEAD, the Codechain head to sign.
- LINE (4-byte), the last signed line number (only from V2 onwards).
- SIGNATURE, signature with PUBKEY.
The SIGNATURE is over all previous fields:
VERSION|PUBKEY|PUBKEY_ROTATE|VALID_FROM|VALID_TO|COUNTER|HEAD|LINE
The signed head is a concatenation of
VERSION|PUBKEY|PUBKEY_ROTATE|VALID_FROM|VALID_TO|COUNTER|HEAD|LINE|SIGNATURE
encoded in base64 (URL encoding without padding).
All integers (VALID_FROM, VALID_TO, COUNTER, LINE) are encoded in network order
(big-endian).
CreatePkg specification
To create a new secure package for a project developed with Codechain that
should be distributed with a SSOT using DNS TXT records, the following
procedure is defined:
1. Make sure the project with NAME has not been published before.
That is, the directory ~/.config/ssotpub/pkgs/NAME does not exist.
2. If TXT records are to be published automatically, check credentials.
3. Test build (see TestBuild specification).
4. Create a new .secpkg file which specifies the following:
- The NAME of the project.
- The fully qualified domain name (DNS) where the TXT records can be
queried.
- The last signed HEAD of the project's Codechain.
The .secpkg file is saved to the current working directory, which is
typically added to the root of the project's repository.
5. Create the first signed head (see SignHead) for the current project's
HEAD with a supplied secret key and counter set to 0.
6. Create the directory ~/.config/ssotpub/pkgs/NAME/dists
and save the current distribution to
~/.config/ssotpub/pkgs/NAME/dists/HEAD.tar.gz (`codechain createdist`).
7. Save the signed head to ~/.config/ssotpub/pkgs/NAME/signed_head
8. Print the distribution name: ~/.config/secpkg/pkgs/NAME/dists/HEAD.tar.gz
9. Print DNS TXT records as defined by the .secpkg, the first signed head,
and the download URL. If TXT records are to be published automatically,
save credentials and publish the TXT record.
Afterwards the administrator manually uploads the distribution HEAD.tar.gz
to the download URL and publishes the new DNS TXT record in the defined
zone (if not published automatically). DNSSEC should be enabled.
SignHead specification
To publish an update of a secure package with SSOT do the following:
1. Parse the .secpkg file in the current working directory.
2. Make sure the project with NAME has been published before.
That is, the directory ~/.config/ssotpub/pkgs/NAME exists.
3. Validate the signed head in ~/.config/ssotpub/pkgs/NAME/signed_head.
4. Get the last signed HEAD from .codechain/hashchain in the current working
directory.
5. If ~/.config/ssotpub/pkgs/NAME/cloudflare.json exits, check the contained
Cloudflare credentials and switch on automatic publishing of TXT records.
6. Test build (see TestBuild specification).
7. If ROTATE is set, check if ~/.config/ssotput/pkgs/NAME/rotate_to exists.
If it does, abort. Otherwise write public key to rotate to and rotate time
(see below) to ~/.config/ssotput/pkgs/NAME/rotate_to.
8. Create a new signed head with current HEAD, the counter of the previous
signed head plus 1, and update the saved signed head:
- `cp -f ~/.config/ssotpub/pkgs/NAME/signed_head
~/.config/ssotpub/pkgs/NAME/previous_signed_head`
- Save new signed head to ~/.config/ssotpub/pkgs/NAME/signed_head (atomic).
If ~/.config/ssotput/pkgs/NAME/rotate_to exists:
- If rotate time has been reached use pubkey from file as PUBKEY and
remove ~/.config/ssotput/pkgs/NAME/rotate_to.
- Otherwise use old PUBKEY and set pubkey from file as PUBKEY_ROTATE.
9. If the HEAD changed, save the current distribution to:
~/.config/secpkg/pkgs/NAME/dists/HEAD.tar.gz (`codechain createdist`).
10. If the HEAD changed, lookup the download URLs and print where to upload
the distribution file:
~/.config/ssotpkg/pkgs/NAME/dists/HEAD.tar.gz
11. Print DNS TXT record as defined by the .secpkg file and the signed head.
If TXT records are to be published automatically, publish the TXT record.
12. If the last signed HEAD changed, update the .secpkg file accordingly.
Afterwards the administrator manually uploads the distribution HEAD.tar.gz
to the download URLs and publishes the new DNS TXT record in the defined
zone (if not published automatically). DNSSEC should be enabled.
Refresh specification
To refresh the published head of a secure package with SSOT do the following:
1. Parse the supplied .secpkg file.
2. Make sure the project with NAME has been published before.
That is, the directory ~/.config/ssotpub/pkgs/NAME exists.
3. Validate the signed head in ~/.config/ssotpub/pkgs/NAME/signed_head.
4. Make sure the signed head in ~/.config/ssotpub/pkgs/NAME/signed_head
matches the last signed HEAD in the .secpkg file.
5. If ~/.config/ssotpub/pkgs/NAME/cloudflare.json exits, check the contained
Cloudflare credentials and switch on automatic publishing of TXT records.
6. If ROTATE is set, check if ~/.config/ssotput/pkgs/NAME/rotate_to exists.
If it does, abort. Otherwise write public key to rotate to and rotate time
(see below) to ~/.config/ssotput/pkgs/NAME/rotate_to.
7. Create a new signed head with the same HEAD, the counter of the previous
signed head plus 1, and update the saved signed head:
- `cp -f ~/.config/ssotpub/pkgs/NAME/signed_head
~/.config/ssotpub/pkgs/NAME/previous_signed_head`
- Save new signed head to ~/.config/ssotpub/pkgs/NAME/signed_head (atomic).
If ~/.config/ssotput/pkgs/NAME/rotate_to exists:
- If rotate time has been reached use pubkey from file as PUBKEY and
remove ~/.config/ssotput/pkgs/NAME/rotate_to.
- Otherwise use old PUBKEY and set pubkey from file as PUBKEY_ROTATE.
8. Print DNS TXT record as defined by the .secpkg file and the signed head.
If TXT record is to be published automatically, publish the TXT record.
Afterwards the administrator publishes the new DNS TXT record in the defined
zone (if not published automatically). DNSSEC should be enabled.
TestBuild specification
To test the build of a secure package do the following:
1. Create temporary directory TMPDIR with `build` and `local` subdirectories.
2. `mkdir TMPDIR/build/.codechain`
3. `cp .codechain/hashchain TMPDIR/build/.codechain`
4. `cp -r .codechain/patches TMPDIR/build/.codechain`
5. `cd TMPDIR/build`
6. `codechain apply`
7. `make prefix=TMPDIR/local`
8. `make prefix=TMPDIR/local install`
9. Make sure TMPDIR/local contains at least one file.
10. `make prefix=TMPDIR/local uninstall`
11. Make sure TMPDIR/local contains no files (but empty directories are OK).
12. Delete temporary directory TMPDIR.
Rotate time calculation
The earliest time a PUBKEY_ROTATE can be used as PUBKEY is when the previous
signed head (without PUBKEY_ROTATE) has expired. This gives clients time to
learn about PUBKEY_ROTATE. To give some extra time we take the time span a
signed head with PUBKEY_ROTATE is valid after the signed head without
PUBKEY_ROTATE has expired and divide it by three. The rotate time is set to the
end of the first third.
*/
package ssot