mailauth 7.1.1 → 7.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.c8rc.json +11 -0
- package/.prettierignore +3 -0
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +68 -0
- package/README.md +131 -31
- package/bin/mailauth.js +62 -0
- package/cli.md +150 -8
- package/docs/arc.md +62 -54
- package/docs/bimi.md +153 -54
- package/docs/dkim.md +37 -36
- package/docs/dkim2.md +154 -0
- package/docs/dmarc.md +4 -1
- package/docs/mta-sts.md +12 -9
- package/docs/spf.md +14 -13
- package/index.d.ts +583 -42
- package/lib/arc/index.d.ts +6 -2
- package/lib/arc/index.js +45 -15
- package/lib/bimi/index.js +362 -102
- package/lib/bimi/validate-svg.js +493 -60
- package/lib/commands/dkim2-hash.js +25 -0
- package/lib/commands/dkim2-sign.js +77 -0
- package/lib/commands/dkim2-verify.js +59 -0
- package/lib/commands/report.js +10 -35
- package/lib/commands/resolver.js +51 -0
- package/lib/commands/seal.js +10 -38
- package/lib/commands/spf.js +4 -35
- package/lib/dkim/dkim-signer.js +50 -30
- package/lib/dkim/dkim-verifier.js +79 -27
- package/lib/dkim/header/simple.js +2 -2
- package/lib/dkim/sign.js +7 -2
- package/lib/dkim/syntax.js +11 -0
- package/lib/dkim/verify.js +1 -0
- package/lib/dkim2/dkim2-parser.js +52 -0
- package/lib/dkim2/dkim2-signer.js +334 -0
- package/lib/dkim2/dkim2-verifier.js +572 -0
- package/lib/dkim2/fields.js +570 -0
- package/lib/dkim2/hash.d.ts +3 -0
- package/lib/dkim2/hash.js +51 -0
- package/lib/dkim2/key.js +203 -0
- package/lib/dkim2/message-state.js +181 -0
- package/lib/dkim2/recipe.js +134 -0
- package/lib/dkim2/sign.d.ts +3 -0
- package/lib/dkim2/sign.js +38 -0
- package/lib/dkim2/verify.d.ts +3 -0
- package/lib/dkim2/verify.js +19 -0
- package/lib/dmarc/author-domain.js +270 -5
- package/lib/dmarc/get-dmarc-record.js +24 -11
- package/lib/dmarc/verify.js +7 -3
- package/lib/mailauth.js +57 -14
- package/lib/mta-sts.js +37 -11
- package/lib/parse-received.js +214 -25
- package/lib/spf/index.js +21 -4
- package/lib/spf/macro.js +5 -3
- package/lib/spf/spf-verify.js +14 -5
- package/lib/spf/syntax.js +5 -0
- package/lib/tools.js +160 -21
- package/package.json +15 -6
- package/stryker.config.json +16 -0
package/cli.md
CHANGED
|
@@ -14,6 +14,9 @@ mailauth provides a command-line utility for email authentication, complementing
|
|
|
14
14
|
- [Available Commands](#available-commands)
|
|
15
15
|
- [`report`](#report) — Validate SPF, DKIM, DMARC, ARC, and BIMI
|
|
16
16
|
- [`sign`](#sign) — Sign an email with DKIM
|
|
17
|
+
- [`dkim2-sign`](#dkim2-sign) — Sign an email with DKIM2 (experimental)
|
|
18
|
+
- [`dkim2-verify`](#dkim2-verify) — Verify the DKIM2 signatures of an email (experimental)
|
|
19
|
+
- [`dkim2-hash`](#dkim2-hash) — Generate the DKIM2 header and body hashes for an email
|
|
17
20
|
- [`seal`](#seal) — Seal an email with ARC
|
|
18
21
|
- [`spf`](#spf) — Validate SPF for an IP address and email address
|
|
19
22
|
- [`vmc`](#vmc) — Validate BIMI VMC logo files
|
|
@@ -56,13 +59,19 @@ mailauth spf --help
|
|
|
56
59
|
|
|
57
60
|
The mailauth CLI offers several commands to perform different email authentication tasks:
|
|
58
61
|
|
|
59
|
-
1. [`report`](#report) — Validate SPF, DKIM, DMARC, ARC, and BIMI.
|
|
62
|
+
1. [`report`](#report) — Validate SPF, DKIM, DMARC, ARC, and BIMI, and optionally DKIM2.
|
|
60
63
|
2. [`sign`](#sign) — Sign an email with DKIM.
|
|
61
|
-
3. [`
|
|
62
|
-
4. [`
|
|
63
|
-
5. [`
|
|
64
|
-
6. [`
|
|
65
|
-
7. [`
|
|
64
|
+
3. [`dkim2-sign`](#dkim2-sign) — Sign an email with DKIM2 (experimental).
|
|
65
|
+
4. [`dkim2-verify`](#dkim2-verify) — Verify the DKIM2 signatures of an email (experimental).
|
|
66
|
+
5. [`dkim2-hash`](#dkim2-hash) — Generate the DKIM2 header and body hashes for an email.
|
|
67
|
+
6. [`seal`](#seal) — Seal an email with ARC.
|
|
68
|
+
7. [`spf`](#spf) — Validate SPF for an IP address and email address.
|
|
69
|
+
8. [`vmc`](#vmc) — Validate BIMI VMC logo files.
|
|
70
|
+
9. [`bodyhash`](#bodyhash) — Generate the body hash value for an email.
|
|
71
|
+
10. [`license`](#license) — Display licenses for mailauth and included modules.
|
|
72
|
+
|
|
73
|
+
> [!WARNING]
|
|
74
|
+
> DKIM2 is not a published RFC yet. The DKIM2 commands are experimental and built against draft-ietf-dkim-dkim2-spec-06, draft-ietf-dkim-dkim2-dns-00 and draft-ietf-dkim-dkim2-bcp-01, see [DKIM2](README.md#dkim2).
|
|
66
75
|
|
|
67
76
|
### report
|
|
68
77
|
|
|
@@ -88,6 +97,8 @@ mailauth report [options] [email]
|
|
|
88
97
|
- `--max-void-lookups number`, `-z number`: Sets the maximum number of void DNS lookups for SPF checks. Defaults to `2`.
|
|
89
98
|
- `--strict`: Follows the RFCs exactly instead of the lenient defaults, for example an `rsa-sha1` DKIM signature is reported as `dkim=policy`. See [Strict mode](README.md#strict-mode).
|
|
90
99
|
- `--reject-rsa-sha1`: Reports an `rsa-sha1` DKIM signature as `dkim=policy` and does not count it for DMARC, as `--strict` does, while every other check keeps the lenient default.
|
|
100
|
+
- `--dkim2`: Verifies DKIM2 header fields as well. The result is in the `dkim2` key of the report and a `dkim2=` entry is added to Authentication-Results. DKIM2 does not take part in DMARC.
|
|
101
|
+
- `--rcpt-to user@example.com`, `-r user@example.com`: RCPT TO address of the delivery, checked against the highest DKIM2-Signature together with `--sender`. Can be repeated. Without it the DKIM2 result has the `rcpt-to-not-checked` warning.
|
|
91
102
|
|
|
92
103
|
#### Example
|
|
93
104
|
|
|
@@ -156,6 +167,137 @@ DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
|
|
|
156
167
|
...
|
|
157
168
|
```
|
|
158
169
|
|
|
170
|
+
### dkim2-sign
|
|
171
|
+
|
|
172
|
+
The `dkim2-sign` command signs an email message with DKIM2. It adds a `DKIM2-Signature` header field, and a `Message-Instance` header field when the message has none yet or has changed since its last instance. Use it as the originator of a message, or as a forwarder that adds its own hop to a message that is already DKIM2 signed.
|
|
173
|
+
|
|
174
|
+
#### Usage
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
mailauth dkim2-sign [options] [email]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- **email**: (Optional) Path to the EML-formatted email message file. If omitted, the email is read from standard input.
|
|
181
|
+
|
|
182
|
+
#### Options
|
|
183
|
+
|
|
184
|
+
- `--private-key /path/to/private.key`, `-k /path/to/private.key`: Path to a private key, RSA (at least 1024 bits) or Ed25519. Repeat it to sign with several keys, each with its own `--selector`.
|
|
185
|
+
- `--selector selector`, `-s selector`: Selector of the private key in the same position. Can be repeated. At most two keys can use the same algorithm.
|
|
186
|
+
- `--domain example.com`, `-d example.com`: Signing domain (`d=` tag). It has to be the MAIL FROM domain or a parent of it.
|
|
187
|
+
- `--mail-from user@example.com`, `-f user@example.com`: MAIL FROM address the message is sent with (`mf=` tag), `<>` for the null sender.
|
|
188
|
+
- `--rcpt-to user@example.net`, `-r user@example.net`: RCPT TO address the message is sent to (`rt=` tag). Can be repeated.
|
|
189
|
+
- `--next-domain example.net`: For a hop across a trust boundary, the domain of the next DKIM2 signature (`nd=` tag). Used instead of `--mail-from` and `--rcpt-to`.
|
|
190
|
+
- `--flag flag`: Flag to set (`f=` tag): `donotmodify`, `donotexplode`, `exploded`, `feedback` or `feedhere`. Can be repeated.
|
|
191
|
+
- `--nonce value`: A value for your own use (`n=` tag), at most 64 characters.
|
|
192
|
+
- `--hash algorithm`: Hash algorithm of a new `Message-Instance`, `sha256` or `sha512`. Can be repeated. Defaults to `sha256`.
|
|
193
|
+
- `--recipe /path/to/recipe.json`: For a forwarder that changed the message, a JSON file with the Recipe that recreates the previous instance (`r=` tag). It is checked before signing, and the command fails if it does not recreate the previous instance.
|
|
194
|
+
- `--time timestamp`, `-t timestamp`: Signing time as a Unix timestamp (`t=` tag). Defaults to the current time.
|
|
195
|
+
- `--headers-only`, `-o`: Outputs only the DKIM2 header fields without the message.
|
|
196
|
+
|
|
197
|
+
Either `--mail-from` and `--rcpt-to`, or `--next-domain`, is required.
|
|
198
|
+
|
|
199
|
+
#### Example
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
mailauth dkim2-sign /path/to/message.eml \
|
|
203
|
+
-k /path/to/rsa.key -s rsa2026 -k /path/to/ed25519.key -s ed2026 \
|
|
204
|
+
-d example.com -f bounces@example.com -r user@example.net
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Sample Output:**
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
DKIM2-Signature: i=1; m=1; t=1791646747; d=example.com; mf=
|
|
211
|
+
PGJvdW5jZXNAZXhhbXBsZS5jb20+; rt=PHVzZXJAZXhhbXBsZS5uZXQ+; s=rsa2026:rsa-sha256:
|
|
212
|
+
MXp6X81Tuu/cwbedt/kFqdO1sE4yPkfYVnFzfBMO2ZjfAtoXuptS+G79SYEpEaAo
|
|
213
|
+
...
|
|
214
|
+
Message-Instance: m=1; h=sha256:
|
|
215
|
+
sbKYVMaA7tqVLzGg5HTTU3o95q7ufdnBincKg/jBBQc=:
|
|
216
|
+
GjyEkbey2OupCW5AKJv4dzTPsPHSaZjRDMqUSmhpTyQ=;
|
|
217
|
+
From: ...
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
A mailing list that replaced the `Subject` header field, added a `List-Id` header field and appended a footer after the first 3 body lines signs its revision with a Recipe:
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{ "h": { "subject": [{ "d": ["Original subject"] }], "list-id": [] }, "b": [{ "c": [1, 3] }] }
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
mailauth dkim2-sign revised.eml -k list.key -s list -d list.example.org \
|
|
228
|
+
-f bounce@list.example.org -r member@example.net --recipe recipe.json
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### dkim2-verify
|
|
232
|
+
|
|
233
|
+
The `dkim2-verify` command verifies only the DKIM2 header fields of an email message and returns a JSON report. See [DKIM2 Result Reference](docs/dkim2.md) for the structure. Use `report --dkim2` to check DKIM2 together with everything else.
|
|
234
|
+
|
|
235
|
+
#### Usage
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
mailauth dkim2-verify [options] [email]
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
- **email**: (Optional) Path to the EML-formatted email message file. If omitted, the email is read from standard input.
|
|
242
|
+
|
|
243
|
+
#### Options
|
|
244
|
+
|
|
245
|
+
- `--mail-from user@example.com`, `-f user@example.com`: MAIL FROM address the message was delivered with, `<>` for the null sender. Checked against the highest DKIM2-Signature.
|
|
246
|
+
- `--rcpt-to user@example.net`, `-r user@example.net`: RCPT TO address the message was delivered to, checked against the highest DKIM2-Signature. Can be repeated.
|
|
247
|
+
- `--dns-cache /path/to/dns.json`, `-n /path/to/dns.json`: Path to a DNS cache file. When provided, DNS queries use cached responses.
|
|
248
|
+
- `--time timestamp`, `-t timestamp`: Time to verify against as a Unix timestamp. Defaults to the current time.
|
|
249
|
+
- `--max-age seconds`: Seconds after which a signature expires, `0` to not check. Defaults to 14 days.
|
|
250
|
+
- `--max-future seconds`: Seconds a signature timestamp may be ahead of the current time, `0` to not check. Defaults to `300`.
|
|
251
|
+
- `--max-instances number`: The most `Message-Instance`, and the most `DKIM2-Signature`, header fields to process. Defaults to `20`.
|
|
252
|
+
- `--headers-only`, `-o`: Outputs only the Authentication-Results entry (`dkim2=...`) instead of the JSON report.
|
|
253
|
+
- `--verbose`, `-v`: Shows the DNS queries, and the parts of the envelope that were not checked.
|
|
254
|
+
|
|
255
|
+
The chain of custody against the delivery, which is what stops DKIM2 replay, is only checked for the parts of the envelope given with `--mail-from` and `--rcpt-to`. A missing part is reported in `status.warnings`.
|
|
256
|
+
|
|
257
|
+
#### Example
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
mailauth dkim2-verify -f bounces@example.com -r user@example.net -o /path/to/message.eml
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Sample Output:**
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
dkim2=pass (i=1 example.com pass) header.d=example.com
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### dkim2-hash
|
|
270
|
+
|
|
271
|
+
The `dkim2-hash` command computes the DKIM2 header and body hashes of an email message, in the `algorithm:header-hash:body-hash` form of the `h=` tag of a `Message-Instance` header field. Use it to check what a `Message-Instance` should contain, for example when writing a Recipe.
|
|
272
|
+
|
|
273
|
+
#### Usage
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
mailauth dkim2-hash [options] [email]
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
- **email**: (Optional) Path to the EML-formatted email message file. If omitted, the email is read from standard input.
|
|
280
|
+
|
|
281
|
+
#### Options
|
|
282
|
+
|
|
283
|
+
- `--algo algorithm`, `-a algorithm`: Hash algorithm, `sha256` or `sha512`. Can be repeated. Defaults to `sha256`.
|
|
284
|
+
- `--verbose`, `-v`: Also lists the header fields that go into the header hash. DKIM2 does not sign trace header fields, `X-` header fields, DKIM1, ARC and Authentication-Results header fields, or its own header fields.
|
|
285
|
+
|
|
286
|
+
#### Example
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
mailauth dkim2-hash -v /path/to/message.eml
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Sample Output:**
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
Reading email message from /path/to/message.eml
|
|
296
|
+
Hashed header fields: content-type, date, from, message-id, mime-version, subject, to
|
|
297
|
+
--------
|
|
298
|
+
sha256:sbKYVMaA7tqVLzGg5HTTU3o95q7ufdnBincKg/jBBQc=:GjyEkbey2OupCW5AKJv4dzTPsPHSaZjRDMqUSmhpTyQ=
|
|
299
|
+
```
|
|
300
|
+
|
|
159
301
|
### seal
|
|
160
302
|
|
|
161
303
|
The `seal` command adds an ARC (Authenticated Received Chain) seal to an email message.
|
|
@@ -185,7 +327,7 @@ mailauth seal [options] [email]
|
|
|
185
327
|
|
|
186
328
|
By default, `seal` authenticates the message (SPF, DKIM, DMARC, ARC) and embeds the computed results in the `ARC-Authentication-Results` header. If the message was already authenticated elsewhere (for example at an edge MTA) and modified afterwards, you can instead provide the original `Authentication-Results` value yourself. When one of the following options is set, no authentication checks or DNS lookups are performed:
|
|
187
329
|
|
|
188
|
-
- `--auth-results "authserv-id; spf=pass ..."`: `Authentication-Results` value to embed in the `ARC-Authentication-Results` header (the part after `i=N;`). Used as is.
|
|
330
|
+
- `--auth-results "authserv-id; spf=pass ..."`: `Authentication-Results` value to embed in the `ARC-Authentication-Results` header (the part after `i=N;`). Used as is, except that line breaks are written as CRLF. A multi-line value must be folded: every line after the first starts with a space or a tab. A value with any other line break is refused, as it would start a new header field.
|
|
189
331
|
- `--auth-results-file /path/to/value.txt`: Same as `--auth-results`, but the value is read from a file. Useful for long or multi-line values. Cannot be combined with `--auth-results`.
|
|
190
332
|
- `--cv status`: Chain validation status for the `ARC-Seal` header (`cv=` tag): `none`, `pass`, or `fail`. Defaults to `none`.
|
|
191
333
|
- `--instance number`: ARC instance number (`i=` tag). Defaults to the next instance number based on the existing ARC chain of the message, or `1`.
|
|
@@ -413,7 +555,7 @@ The `--dns-cache` option allows you to use a JSON-formatted DNS cache file for t
|
|
|
413
555
|
|
|
414
556
|
The DNS cache file is a JSON object where:
|
|
415
557
|
|
|
416
|
-
- **Keys**: Fully qualified domain names (e.g., `"example.com"`).
|
|
558
|
+
- **Keys**: Fully qualified domain names (e.g., `"example.com"`). DKIM and DKIM2 keys are looked up as `selector._domainkey.domain`.
|
|
417
559
|
- **Values**: Objects with DNS record types as keys (e.g., `"TXT"`, `"MX"`) and their corresponding values.
|
|
418
560
|
|
|
419
561
|
**Example:**
|
package/docs/arc.md
CHANGED
|
@@ -31,13 +31,13 @@ With `strict: true` the validation and sealing follow RFC 8617 exactly, see [Str
|
|
|
31
31
|
|
|
32
32
|
## status Object
|
|
33
33
|
|
|
34
|
-
| Field | Type | Presence | Description
|
|
35
|
-
| ------------ | --------- | ------------ |
|
|
36
|
-
| `result` | `string` | Always | ARC result code (see below)
|
|
37
|
-
| `comment` | `string` | On pass/fail | Description or error message
|
|
38
|
-
| `shouldSeal` | `boolean` | On fail | Whether
|
|
39
|
-
| `policy` | `object` | Policy issue | Policy violation details (e.g., `{"dkim-rules": "weak-key"}`)
|
|
40
|
-
| `smtp` | `object` | Strict mode | `{"remote-ip": "192.0.2.1"}`, the client IP (RFC 8617 section 6)
|
|
34
|
+
| Field | Type | Presence | Description |
|
|
35
|
+
| ------------ | --------- | ------------ | -------------------------------------------------------------------------------------------------------- |
|
|
36
|
+
| `result` | `string` | Always | ARC result code (see below) |
|
|
37
|
+
| `comment` | `string` | On pass/fail | Description or error message |
|
|
38
|
+
| `shouldSeal` | `boolean` | On fail | Whether the failed chain is sealed with `cv=fail`, false when its newest ARC-Seal already says `cv=fail` |
|
|
39
|
+
| `policy` | `object` | Policy issue | Policy violation details (e.g., `{"dkim-rules": "weak-key"}`) |
|
|
40
|
+
| `smtp` | `object` | Strict mode | `{"remote-ip": "192.0.2.1"}`, the client IP (RFC 8617 section 6) |
|
|
41
41
|
|
|
42
42
|
## authenticationResults Object
|
|
43
43
|
|
|
@@ -61,28 +61,29 @@ When ARC validation passes, the `authenticationResults` object contains parsed r
|
|
|
61
61
|
|
|
62
62
|
## Comment Values (on failure)
|
|
63
63
|
|
|
64
|
-
| Comment Pattern | Description
|
|
65
|
-
| --------------------------------------------------------------------------- |
|
|
66
|
-
| `"i={n} seal signature validation failed"` | ARC-Seal cryptographic verification failed
|
|
67
|
-
| `"i={n} no valid signature"` | ARC-Message-Signature verification failed
|
|
68
|
-
| `"i={n} multiple {header} values"` | Duplicate ARC headers for same instance
|
|
69
|
-
| `"chain-length={n}"` | Chain exceeds 50 instances
|
|
70
|
-
| `"i={n} expected={m}"` | Missing or out-of-order instance numbers
|
|
71
|
-
| `"i={n} no {header} set"` | Missing required ARC header
|
|
72
|
-
| `"i=1 cv={value}"` | First instance must have `cv=none`
|
|
73
|
-
| `"i={n} cv={value}"` | Non-first instance must have `cv=pass`, and a newest seal with `cv=fail` fails the chain
|
|
74
|
-
| `"i={n} unexpected as h"` | ARC-Seal has an `h=` tag
|
|
75
|
-
| `"i={n} invalid ams h"` | ARC-Message-Signature signed arc-seal (forbidden)
|
|
76
|
-
| `"i={n} as {problem}"`, `"i={n} ams {problem}"` | Strict mode: a tag-list syntax error, a missing required tag or a malformed `t=`/`x=`/`l=`
|
|
77
|
-
| `"
|
|
78
|
-
| `"
|
|
79
|
-
| `"
|
|
80
|
-
| `"unknown key
|
|
81
|
-
| `"
|
|
82
|
-
| `"
|
|
83
|
-
| `"
|
|
84
|
-
| `"
|
|
85
|
-
| `"
|
|
64
|
+
| Comment Pattern | Description |
|
|
65
|
+
| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
66
|
+
| `"i={n} seal signature validation failed"` | ARC-Seal cryptographic verification failed |
|
|
67
|
+
| `"i={n} no valid signature"` | ARC-Message-Signature verification failed |
|
|
68
|
+
| `"i={n} multiple {header} values"` | Duplicate ARC headers for same instance |
|
|
69
|
+
| `"chain-length={n}"` | Chain exceeds 50 instances |
|
|
70
|
+
| `"i={n} expected={m}"` | Missing or out-of-order instance numbers |
|
|
71
|
+
| `"i={n} no {header} set"` | Missing required ARC header |
|
|
72
|
+
| `"i=1 cv={value}"` | First instance must have `cv=none` |
|
|
73
|
+
| `"i={n} cv={value}"` | Non-first instance must have `cv=pass`, and a newest seal with `cv=fail` fails the chain |
|
|
74
|
+
| `"i={n} unexpected as h"` | ARC-Seal has an `h=` tag |
|
|
75
|
+
| `"i={n} invalid ams h"` | ARC-Message-Signature signed arc-seal (forbidden) |
|
|
76
|
+
| `"i={n} as {problem}"`, `"i={n} ams {problem}"` | Strict mode: a tag-list syntax error, a missing required tag or a malformed `t=`/`x=`/`l=` |
|
|
77
|
+
| `"i={n} as invalid d="`, `"i={n} ams invalid d="` | Both modes: an ARC-Seal or the newest ARC-Message-Signature has a `d=` with a character that can not be in a host name |
|
|
78
|
+
| `"invalid as instance"`, `"invalid ams instance"`, `"invalid aar instance"` | Strict mode: an ARC header field whose `i=` is not 1 to 50 written as 1*2DIGIT (first in ARC-Authentication-Results) |
|
|
79
|
+
| `"no key for {domain}"` | DNS key not found |
|
|
80
|
+
| `"unknown key version for {domain}"` | Key record `v=` is not `DKIM1` |
|
|
81
|
+
| `"unknown key type for {domain}"` | Unsupported key type |
|
|
82
|
+
| `"invalid public key for {domain}"` | Malformed public key |
|
|
83
|
+
| `"inappropriate hash algorithm for {domain}"` | Key record `h=` does not list sha256 |
|
|
84
|
+
| `"key not for email for {domain}"` | Key record `s=` does not list email |
|
|
85
|
+
| `"inappropriate key algorithm for {domain}"` | The key type does not match the seal's `a=` algorithm |
|
|
86
|
+
| `"weak key for {domain}"` | RSA key too short |
|
|
86
87
|
|
|
87
88
|
An ARC-Message-Signature that does not sign the From header field is not valid (RFC 6376 section 6.1.1), which fails the chain with `"i={n} no valid signature"` in both modes. An ARC-Seal `c=` tag is not defined by RFC 8617, so it is ignored like any other unknown tag.
|
|
88
89
|
|
|
@@ -94,6 +95,7 @@ These rules apply in both modes:
|
|
|
94
95
|
- An Ed25519 seal signs the SHA-256 hash of the canonicalized data (RFC 8463).
|
|
95
96
|
- The seal's `a=` algorithm has to match the key type, and the key record's `v=`, `h=` and `s=` tags are honored.
|
|
96
97
|
- An ARC-Message-Signature without `c=` uses `simple/simple`, the DKIM-Signature default.
|
|
98
|
+
- A `d=` with a character that can not be in a host name (such as `/`, `?`, `#`, `@` or `:`) in any ARC-Seal or in the newest ARC-Message-Signature fails the chain, and its key is not looked up.
|
|
97
99
|
|
|
98
100
|
Differences between the modes:
|
|
99
101
|
|
|
@@ -115,12 +117,12 @@ The position of `i=` in an ARC-Seal or ARC-Message-Signature is not checked in e
|
|
|
115
117
|
|
|
116
118
|
In the default mode `warnings` lists what was accepted although strict mode would have rejected it. It is only present when there is something to report and the chain did not fail, and it is never written into the Authentication-Results text.
|
|
117
119
|
|
|
118
|
-
| Warning
|
|
119
|
-
|
|
|
120
|
-
| `arc-tag-syntax`
|
|
121
|
-
| `arc-instance-syntax`
|
|
122
|
-
| `ams-c-default`
|
|
123
|
-
| `key-syntax`, `key-v-syntax`, `key-type-inferred` | Key record leniencies, see the [DKIM result reference](dkim.md#warnings) |
|
|
120
|
+
| Warning | Meaning |
|
|
121
|
+
| --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
122
|
+
| `arc-tag-syntax` | An ARC-Seal or the newest ARC-Message-Signature has a tag-list syntax error or an upper case tag name |
|
|
123
|
+
| `arc-instance-syntax` | An `i=` value is not valid RFC 8617 syntax, or an ARC header field was ignored because of its `i=` |
|
|
124
|
+
| `ams-c-default` | The ARC-Message-Signature has no `c=` and only verified with `relaxed/relaxed` |
|
|
125
|
+
| `key-syntax`, `key-v-syntax`, `key-type-inferred`, `key-ed25519-spki` | Key record leniencies, see the [DKIM result reference](dkim.md#warnings) |
|
|
124
126
|
|
|
125
127
|
## Sealing
|
|
126
128
|
|
|
@@ -131,31 +133,37 @@ In the default mode `warnings` lists what was accepted although strict mode woul
|
|
|
131
133
|
| `headers` | `string[]` | ARC headers to prepend: `[ARC-Seal, ARC-Message-Signature, ARC-Authentication-Results]`, or empty |
|
|
132
134
|
| `errors` | `array` | `{ err, type, selector, signingDomain }` entries saying why no set was created |
|
|
133
135
|
| `warnings` | `string[]` | What the default mode sealed that strict mode would have refused |
|
|
136
|
+
| `instance` | `number` | The instance (`i=`) of the created set, not set when no set was created |
|
|
134
137
|
|
|
135
138
|
Seal options:
|
|
136
139
|
|
|
137
|
-
| Option | Type | Description
|
|
138
|
-
| --------------- | ------------------ |
|
|
139
|
-
| `signingDomain` | `string` | `d=` value
|
|
140
|
-
| `selector` | `string` | `s=` value
|
|
141
|
-
| `privateKey` | `string\|Buffer` | RSA or Ed25519 private key
|
|
142
|
-
| `algorithm` | `string` | `rsa-sha256` or `ed25519-sha256`, follows the key type when not set
|
|
143
|
-
| `authResults` | `string` | The Authentication-Results payload for the ARC-Authentication-Results header
|
|
144
|
-
| `cv` | `string` | `none`, `pass` or `fail`. Defaults to `none` for the first set, required for later ones
|
|
145
|
-
| `i` | `number` | Instance, defaults to one more than the highest instance on the message
|
|
146
|
-
| `headerList` | `string\|string[]` | Header fields for the ARC-Message-Signature. ARC header fields and Authentication-Results are never signed
|
|
147
|
-
| `signTime` | `Date` | Signing time
|
|
148
|
-
| `strict` | `boolean` | Follow the RFCs exactly
|
|
140
|
+
| Option | Type | Description |
|
|
141
|
+
| --------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------- |
|
|
142
|
+
| `signingDomain` | `string` | `d=` value |
|
|
143
|
+
| `selector` | `string` | `s=` value |
|
|
144
|
+
| `privateKey` | `string\|Buffer` | RSA or Ed25519 private key |
|
|
145
|
+
| `algorithm` | `string` | `rsa-sha256` or `ed25519-sha256`, follows the key type when not set |
|
|
146
|
+
| `authResults` | `string` | The Authentication-Results payload for the ARC-Authentication-Results header (required). Line breaks only as CRLF folding |
|
|
147
|
+
| `cv` | `string` | `none`, `pass` or `fail`. Defaults to `none` for the first set, required for later ones |
|
|
148
|
+
| `i` | `number` | Instance, defaults to one more than the highest instance on the message |
|
|
149
|
+
| `headerList` | `string\|string[]` | Header fields for the ARC-Message-Signature. ARC header fields and Authentication-Results are never signed |
|
|
150
|
+
| `signTime` | `Date` | Signing time |
|
|
151
|
+
| `strict` | `boolean` | Follow the RFCs exactly |
|
|
152
|
+
|
|
153
|
+
`authenticate()` always computes `authResults`, `cv` and `i` for the message it seals and ignores these values in its `seal` option. The seal options object is never modified, so one object can be shared by concurrent calls.
|
|
154
|
+
|
|
155
|
+
A name repeated in `headerList` is over-signed in the ARC-Message-Signature, as with `dkimSign`.
|
|
149
156
|
|
|
150
157
|
No ARC set is created (in either mode) when:
|
|
151
158
|
|
|
152
|
-
| Error code
|
|
153
|
-
|
|
|
154
|
-
| `EARCCHAINFAILED`
|
|
155
|
-
| `EINVALIDINSTANCE`
|
|
156
|
-
| `EINVALIDCV`
|
|
157
|
-
| `EINVALIDALGO`
|
|
158
|
-
| `
|
|
159
|
+
| Error code | Reason |
|
|
160
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
161
|
+
| `EARCCHAINFAILED` | The newest ARC-Seal on the message already has `cv=fail` (RFC 8617 section 5.1 step 2) |
|
|
162
|
+
| `EINVALIDINSTANCE` | The instance is not 1 to 50, already exists on the message, or the chain already has 50 sets |
|
|
163
|
+
| `EINVALIDCV` | `cv` is not `none`, `pass` or `fail`, is missing for an instance above 1, or is `pass` while the chain on the message could not be parsed |
|
|
164
|
+
| `EINVALIDALGO` | The algorithm is not `rsa-sha256` or `ed25519-sha256` |
|
|
165
|
+
| `EINVALIDAUTHRESULTS` | `authResults` is missing or empty, or has a line break that is not folding (CRLF followed by a space or tab and more text) |
|
|
166
|
+
| `EINVALIDTYPE` | The algorithm does not match the key type |
|
|
159
167
|
|
|
160
168
|
What only strict mode refuses (the default mode seals and adds the warning):
|
|
161
169
|
|