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
//! **The grade, read off this box's own certificate before anything is
//! dialled** (yog's `docs/REMOTE.md` §4.2; DESIGN §4.4).
//!
//! REMOTE §4.2 gives a certificate one of two grades and gives the grade one
//! home — *"the subject's organizational unit, read by the walk that already
//! reads the common name: `CN=<client>, OU=foot` is a foot"*. A seat is
//! **operator grade by definition**: *"a face that could not ask is not a
//! face"* (§2). So a seat configured with a foot-grade leaf is a
//! misconfiguration, and it is one this box can see in its own files.
//!
//! # This is a DIAGNOSIS and not an enforcement, and the difference decides
//! every line below
//!
//! Enforcement is the **engine's**, at the chokepoint where the client identity
//! is already spent for scoping, fail-closed and in band. A seat holding a
//! foot-grade leaf is therefore already refused, correctly, with or without
//! this file. Nothing here is a security property and nothing here may behave
//! as though it were.
//!
//! What is missing without it is a **sentence**. That refusal arrives as an
//! authorization answer from the far end, about a fault that is entirely this
//! box's own configuration — the operator pointed a seat at the wrong pair.
//! Reading the grade here turns it into a sentence about a file on this disk,
//! before a socket is opened.
//!
//! # So it identifies one fault; it never validates
//!
//! [`refusal`] answers `Some` **only** where it positively read `OU=foot`, and
//! `None` for everything else — bytes that are not a certificate, a subject it
//! cannot walk, an attribute in a string type it will not decode. That is the
//! whole shape of it, and it is what keeps a diagnostic aid from becoming an
//! outage: a walk that refused what it could not read would be a second, weaker
//! certificate parser standing in front of rustls, refusing leaves the engine
//! would have accepted. **Default-operator is REMOTE §4.2's own rule** — a
//! certificate minted before the grade existed keeps working — and reading it
//! any other way here would be this end inventing a policy the authority does
//! not have.
//!
//! The sibling foot component does the mirror of this and fails **closed**,
//! which is not a disagreement: its obligation is to carry a foot leaf and
//! refuse to be configured with anything else, so an unreadable leaf is a
//! refusal there and is silence here. The two ends answer different questions.
//!
//! # The walk, and why it is structural
//!
//! This crate links no certificate library beyond rustls' own PEM reader, so
//! the grade is read by a DER walk — structural ASN.1 rather than a byte
//! search, and the structure is the point: the **issuer** carries a common name
//! too and it comes FIRST, so a scan for the common-name object identifier
//! would answer the operator CA's name for every leaf on the box.
//!
//! What it reads, per RFC 5280:
//!
//! ```text
//! Certificate ::= SEQUENCE { tbsCertificate, signatureAlgorithm, signature }
//! TBSCertificate ::= SEQUENCE { [0] version OPTIONAL, serialNumber INTEGER,
//! signature, issuer, validity, subject, … }
//! Name ::= SEQUENCE OF SET OF SEQUENCE { type OID, value ANY }
//! ```
//!
//! The optional `[0] version` is why `subject` is located **relative to the
//! serial number** rather than at a fixed index: the serial is the first field
//! certainly present, and `subject` is four constructed values past it. A
//! version-1 certificate and a version-3 one then take one path, not two.
use Path;
/// DER tags this walk names.
const INTEGER: u8 = 0x02;
const OID: u8 = 0x06;
/// `id-at-commonName` — ASN.1 `{joint-iso-itu-t(2) ds(5) attributeType(4)
/// commonName(3)}`, in its DER encoding. Spelled as bytes rather than as the
/// dotted arc string because the dotted form of four small arcs is
/// indistinguishable from an IPv4 address, to a reader and to `make leak-scan`.
const COMMON_NAME: = ;
/// `id-at-organizationalUnitName` — the same arc one attribute over, and the
/// home REMOTE §4.2 gives the grade.
const ORG_UNIT: = ;
/// The organizational unit that says foot. One word, written by the operator's
/// CA or not at all.
const FOOT: &str = "foot";
/// How many constructed fields separate `serialNumber` from `subject`:
/// signature, issuer, validity, subject.
const SERIAL_TO_SUBJECT: usize = 4;
/// **The one misconfiguration this box can name on its own**, as the sentence
/// to answer with — or `None`, which is every other leaf and every byte string
/// this walk cannot read.
///
/// `at` is the file the bytes came out of, because the whole value of saying
/// this locally is naming the file the operator has to replace.
/// Whether the subject says foot.
/// The subject common name — the client identity the engine reads back off the
/// presented certificate (REMOTE §2), so a seat that says its own name learned
/// it from the same bytes the engine will.
///
/// The **last** common name wins. A distinguished name is written most-general
/// first in DER and most-specific last (RFC 4514 renders it reversed), so the
/// final one is the leaf's own.
/// The `Name` bytes of the certificate's **subject** — located relative to the
/// serial number, for the reason the module doc gives.
/// Every value of attribute `oid` in a `Name`, in DER order, decoded as UTF-8.
/// Every string type these attributes are minted in — `UTF8String`,
/// `PrintableString`, `IA5String` — is UTF-8 or a subset of it, and one that is
/// not (`BMPString` is UTF-16) fails the decode and is skipped rather than
/// mis-read.
/// One DER type-length-value off the front of `bytes`: its tag, its contents,
/// and what follows it. `None` for a truncated header, a truncated value, or a
/// length DER does not permit — the indefinite form (`0x80`), which BER allows
/// and DER forbids, and a length wider than this walk will serve.
/// Every element of a constructed value, in order. A trailing byte run that is
/// not a whole TLV ends the walk — a malformed tail yields the elements read
/// before it, which is what makes every read above total.