cddlc 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/data/rfc8927.cddl ADDED
@@ -0,0 +1,96 @@
1
+
2
+ ; root-schema is identical to schema, but additionally allows for
3
+ ; definitions.
4
+ ;
5
+ ; definitions are prohibited from appearing on non-root schemas.
6
+ root-schema = {
7
+ ? definitions: { * tstr => { schema}},
8
+ schema,
9
+ }
10
+ ; schema is the main CDDL rule defining a JTD schema.
11
+ ;
12
+ ; All JTD schemas are JSON objects taking on one of eight forms
13
+ ; listed here.
14
+ schema = (
15
+ ref //
16
+ type //
17
+ enum //
18
+ elements //
19
+ properties //
20
+ values //
21
+ discriminator //
22
+ empty //
23
+ )
24
+ ; shared is a CDDL rule containing properties that all eight schema
25
+ ; forms share.
26
+ shared = (
27
+ ? metadata: { * tstr => any },
28
+ ? nullable: bool,
29
+ )
30
+ ; empty describes the "empty" schema form.
31
+ empty = shared
32
+ ; ref describes the "ref" schema form.
33
+ ;
34
+ ; There are additional constraints on this form that cannot be
35
+ ; expressed in CDDL. Section 2.2.2 describes these additional
36
+ ; constraints in detail.
37
+ ref = ( ref: tstr, shared )
38
+ ; type describes the "type" schema form.
39
+ type = (
40
+ type: "boolean"
41
+ / "float32"
42
+ / "float64"
43
+ / "int8"
44
+ / "uint8"
45
+ / "int16"
46
+ / "uint16"
47
+ / "int32"
48
+ / "uint32"
49
+ / "string"
50
+ / "timestamp",
51
+ shared,
52
+ )
53
+ ; enum describes the "enum" schema form.
54
+ ;
55
+ ; There are additional constraints on this form that cannot be
56
+ ; expressed in CDDL. Section 2.2.4 describes these additional
57
+ ; constraints in detail.
58
+ enum = ( enum: [+ tstr], shared )
59
+ ; elements describes the "elements" schema form.
60
+ elements = ( elements: { schema }, shared )
61
+ ; properties describes the "properties" schema form.
62
+ ;
63
+ ; This CDDL rule is defined so that a schema of the "properties" form
64
+ ; may omit a member named "properties" or a member named
65
+ ; "optionalProperties", but not both.
66
+ ;
67
+ ; There are additional constraints on this form that cannot be
68
+ ; expressed in CDDL. Section 2.2.6 describes these additional
69
+ ; constraints in detail.
70
+ properties = (with-properties // with-optional-properties)
71
+ with-properties = (
72
+ properties: { * tstr => { schema }},
73
+ ? optionalProperties: { * tstr => { schema }},
74
+ ? additionalProperties: bool,
75
+ shared,
76
+ )
77
+ with-optional-properties = (
78
+ ? properties: { * tstr => { schema }},
79
+ optionalProperties: { * tstr => { schema }},
80
+ ? additionalProperties: bool,
81
+ shared,
82
+ )
83
+ ; values describes the "values" schema form.
84
+ values = ( values: { schema }, shared )
85
+ ; discriminator describes the "discriminator" schema form.
86
+ ;
87
+ ; There are additional constraints on this form that cannot be
88
+ ; expressed in CDDL. Section 2.2.8 describes these additional
89
+ ; constraints in detail.
90
+ discriminator = (
91
+ discriminator: tstr,
92
+ ; Note well: this rule is defined in terms of the "properties"
93
+ ; CDDL rule, not the "schema" CDDL rule.
94
+ mapping: { * tstr => { properties } }
95
+ shared,
96
+ )
data/data/rfc8990.cddl ADDED
@@ -0,0 +1,213 @@
1
+
2
+ grasp-message = (message .within message-structure) / noop-message
3
+
4
+ message-structure = [MESSAGE_TYPE, session-id, ?initiator,
5
+ *grasp-option]
6
+
7
+ MESSAGE_TYPE = 0..255
8
+ session-id = 0..4294967295 ; up to 32 bits
9
+ grasp-option = any
10
+
11
+
12
+ discovery-message = [M_DISCOVERY, session-id, initiator, objective]
13
+
14
+
15
+ response-message = [M_RESPONSE, session-id, initiator, ttl,
16
+ (+locator-option // divert-option), ?objective]
17
+
18
+ ttl = 0..4294967295 ; in milliseconds
19
+
20
+
21
+ request-negotiation-message = [M_REQ_NEG, session-id, objective]
22
+
23
+ request-synchronization-message = [M_REQ_SYN, session-id, objective]
24
+
25
+
26
+ negotiation-message = [M_NEGOTIATE, session-id, objective]
27
+
28
+
29
+ end-message = [M_END, session-id, accept-option / decline-option]
30
+
31
+
32
+ wait-message = [M_WAIT, session-id, waiting-time]
33
+ waiting-time = 0..4294967295 ; in milliseconds
34
+
35
+
36
+ synch-message = [M_SYNCH, session-id, objective]
37
+
38
+
39
+ flood-message = [M_FLOOD, session-id, initiator, ttl,
40
+ +[objective, (locator-option / [])]]
41
+
42
+ ttl = 0..4294967295 ; in milliseconds
43
+
44
+
45
+ invalid-message = [M_INVALID, session-id, ?any]
46
+
47
+
48
+ noop-message = [M_NOOP]
49
+
50
+
51
+ divert-option = [O_DIVERT, +locator-option]
52
+
53
+
54
+ accept-option = [O_ACCEPT]
55
+
56
+
57
+ decline-option = [O_DECLINE, ?reason]
58
+ reason = text ; optional UTF-8 error message
59
+
60
+
61
+ ipv6-locator-option = [O_IPv6_LOCATOR, ipv6-address,
62
+ transport-proto, port-number]
63
+ ipv6-address = bytes .size 16
64
+
65
+ transport-proto = IPPROTO_TCP / IPPROTO_UDP
66
+ IPPROTO_TCP = 6
67
+ IPPROTO_UDP = 17
68
+ port-number = 0..65535
69
+
70
+
71
+ ipv4-locator-option = [O_IPv4_LOCATOR, ipv4-address,
72
+ transport-proto, port-number]
73
+ ipv4-address = bytes .size 4
74
+
75
+
76
+ fqdn-locator-option = [O_FQDN_LOCATOR, text,
77
+ transport-proto, port-number]
78
+
79
+
80
+ uri-locator-option = [O_URI_LOCATOR, text,
81
+ transport-proto / null, port-number / null]
82
+
83
+
84
+ objective = [objective-name, objective-flags,
85
+ loop-count, ?objective-value]
86
+
87
+ objective-name = text
88
+ objective-value = any
89
+ loop-count = 0..255
90
+
91
+
92
+ objective-flags = uint .bits objective-flag
93
+ objective-flag = &(
94
+ F_DISC: 0 ; valid for discovery
95
+ F_NEG: 1 ; valid for negotiation
96
+ F_SYNCH: 2 ; valid for synchronization
97
+ F_NEG_DRY: 3 ; negotiation is a dry run
98
+ )
99
+
100
+
101
+ grasp-message = (message .within message-structure) / noop-message
102
+
103
+ message-structure = [MESSAGE_TYPE, session-id, ?initiator,
104
+ *grasp-option]
105
+
106
+ MESSAGE_TYPE = 0..255
107
+ session-id = 0..4294967295 ; up to 32 bits
108
+ grasp-option = any
109
+
110
+ message /= discovery-message
111
+ discovery-message = [M_DISCOVERY, session-id, initiator, objective]
112
+
113
+ message /= response-message ; response to Discovery
114
+ response-message = [M_RESPONSE, session-id, initiator, ttl,
115
+ (+locator-option // divert-option), ?objective]
116
+
117
+ message /= synch-message ; response to Synchronization request
118
+ synch-message = [M_SYNCH, session-id, objective]
119
+
120
+ message /= flood-message
121
+ flood-message = [M_FLOOD, session-id, initiator, ttl,
122
+ +[objective, (locator-option / [])]]
123
+
124
+ message /= request-negotiation-message
125
+ request-negotiation-message = [M_REQ_NEG, session-id, objective]
126
+
127
+ message /= request-synchronization-message
128
+ request-synchronization-message = [M_REQ_SYN, session-id, objective]
129
+
130
+ message /= negotiation-message
131
+ negotiation-message = [M_NEGOTIATE, session-id, objective]
132
+
133
+ message /= end-message
134
+ end-message = [M_END, session-id, accept-option / decline-option]
135
+
136
+ message /= wait-message
137
+ wait-message = [M_WAIT, session-id, waiting-time]
138
+
139
+ message /= invalid-message
140
+ invalid-message = [M_INVALID, session-id, ?any]
141
+
142
+ noop-message = [M_NOOP]
143
+
144
+ divert-option = [O_DIVERT, +locator-option]
145
+
146
+ accept-option = [O_ACCEPT]
147
+
148
+ decline-option = [O_DECLINE, ?reason]
149
+ reason = text ; optional UTF-8 error message
150
+
151
+ waiting-time = 0..4294967295 ; in milliseconds
152
+ ttl = 0..4294967295 ; in milliseconds
153
+
154
+ locator-option /= [O_IPv4_LOCATOR, ipv4-address,
155
+ transport-proto, port-number]
156
+ ipv4-address = bytes .size 4
157
+
158
+ locator-option /= [O_IPv6_LOCATOR, ipv6-address,
159
+ transport-proto, port-number]
160
+ ipv6-address = bytes .size 16
161
+
162
+ locator-option /= [O_FQDN_LOCATOR, text, transport-proto,
163
+ port-number]
164
+
165
+ locator-option /= [O_URI_LOCATOR, text,
166
+ transport-proto / null, port-number / null]
167
+
168
+ transport-proto = IPPROTO_TCP / IPPROTO_UDP
169
+ IPPROTO_TCP = 6
170
+ IPPROTO_UDP = 17
171
+ port-number = 0..65535
172
+
173
+ initiator = ipv4-address / ipv6-address
174
+
175
+ objective-flags = uint .bits objective-flag
176
+
177
+ objective-flag = &(
178
+ F_DISC: 0 ; valid for discovery
179
+ F_NEG: 1 ; valid for negotiation
180
+ F_SYNCH: 2 ; valid for synchronization
181
+ F_NEG_DRY: 3 ; negotiation is a dry run
182
+ )
183
+
184
+ objective = [objective-name, objective-flags,
185
+ loop-count, ?objective-value]
186
+
187
+ objective-name = text ; see section "Format of Objective Options"
188
+
189
+ objective-value = any
190
+
191
+ loop-count = 0..255
192
+
193
+ ; Constants for message types and option types
194
+
195
+ M_NOOP = 0
196
+ M_DISCOVERY = 1
197
+ M_RESPONSE = 2
198
+ M_REQ_NEG = 3
199
+ M_REQ_SYN = 4
200
+ M_NEGOTIATE = 5
201
+ M_END = 6
202
+ M_WAIT = 7
203
+ M_SYNCH = 8
204
+ M_FLOOD = 9
205
+ M_INVALID = 99
206
+
207
+ O_DIVERT = 100
208
+ O_ACCEPT = 101
209
+ O_DECLINE = 102
210
+ O_IPv6_LOCATOR = 103
211
+ O_IPv4_LOCATOR = 104
212
+ O_FQDN_LOCATOR = 105
213
+ O_URI_LOCATOR = 106
data/data/rfc9052.cddl ADDED
@@ -0,0 +1,154 @@
1
+
2
+ start = COSE_Messages / COSE_Key / COSE_KeySet / Internal_Types
3
+
4
+ ; This is defined to make the tool quieter:
5
+ Internal_Types = Sig_structure / Enc_structure / MAC_structure
6
+
7
+
8
+ label = int / tstr
9
+ values = any
10
+
11
+
12
+ COSE_Messages = COSE_Untagged_Message / COSE_Tagged_Message
13
+
14
+ COSE_Untagged_Message = COSE_Sign / COSE_Sign1 /
15
+ COSE_Encrypt / COSE_Encrypt0 /
16
+ COSE_Mac / COSE_Mac0
17
+
18
+ COSE_Tagged_Message = COSE_Sign_Tagged / COSE_Sign1_Tagged /
19
+ COSE_Encrypt_Tagged / COSE_Encrypt0_Tagged /
20
+ COSE_Mac_Tagged / COSE_Mac0_Tagged
21
+
22
+
23
+ Headers = (
24
+ protected : empty_or_serialized_map,
25
+ unprotected : header_map
26
+ )
27
+
28
+ header_map = {
29
+ Generic_Headers,
30
+ * label => values
31
+ }
32
+
33
+ empty_or_serialized_map = bstr .cbor header_map / bstr .size 0
34
+
35
+
36
+
37
+ Generic_Headers = (
38
+ ? 1 => int / tstr, ; algorithm identifier
39
+ ? 2 => [+label], ; criticality
40
+ ? 3 => tstr / int, ; content type
41
+ ? 4 => bstr, ; key identifier
42
+ ? ( 5 => bstr // ; IV
43
+ 6 => bstr ) ; Partial IV
44
+ )
45
+
46
+
47
+ COSE_Sign_Tagged = #6.98(COSE_Sign)
48
+
49
+
50
+ COSE_Sign = [
51
+ Headers,
52
+ payload : bstr / nil,
53
+ signatures : [+ COSE_Signature]
54
+ ]
55
+
56
+
57
+ COSE_Signature = [
58
+ Headers,
59
+ signature : bstr
60
+ ]
61
+
62
+
63
+ COSE_Sign1_Tagged = #6.18(COSE_Sign1)
64
+
65
+
66
+ COSE_Sign1 = [
67
+ Headers,
68
+ payload : bstr / nil,
69
+ signature : bstr
70
+ ]
71
+
72
+
73
+ Sig_structure = [
74
+ context : "Signature" / "Signature1",
75
+ body_protected : empty_or_serialized_map,
76
+ ? sign_protected : empty_or_serialized_map,
77
+ external_aad : bstr,
78
+ payload : bstr
79
+ ]
80
+
81
+
82
+ COSE_Encrypt_Tagged = #6.96(COSE_Encrypt)
83
+
84
+
85
+ COSE_Encrypt = [
86
+ Headers,
87
+ ciphertext : bstr / nil,
88
+ recipients : [+COSE_recipient]
89
+ ]
90
+
91
+
92
+ COSE_recipient = [
93
+ Headers,
94
+ ciphertext : bstr / nil,
95
+ ? recipients : [+COSE_recipient]
96
+ ]
97
+
98
+
99
+ COSE_Encrypt0_Tagged = #6.16(COSE_Encrypt0)
100
+
101
+
102
+ COSE_Encrypt0 = [
103
+ Headers,
104
+ ciphertext : bstr / nil,
105
+ ]
106
+
107
+
108
+ Enc_structure = [
109
+ context : "Encrypt" / "Encrypt0" / "Enc_Recipient" /
110
+ "Mac_Recipient" / "Rec_Recipient",
111
+ protected : empty_or_serialized_map,
112
+ external_aad : bstr
113
+ ]
114
+
115
+
116
+ COSE_Mac_Tagged = #6.97(COSE_Mac)
117
+
118
+
119
+ COSE_Mac = [
120
+ Headers,
121
+ payload : bstr / nil,
122
+ tag : bstr,
123
+ recipients : [+COSE_recipient]
124
+ ]
125
+
126
+
127
+ COSE_Mac0_Tagged = #6.17(COSE_Mac0)
128
+
129
+
130
+ COSE_Mac0 = [
131
+ Headers,
132
+ payload : bstr / nil,
133
+ tag : bstr,
134
+ ]
135
+
136
+
137
+ MAC_structure = [
138
+ context : "MAC" / "MAC0",
139
+ protected : empty_or_serialized_map,
140
+ external_aad : bstr,
141
+ payload : bstr
142
+ ]
143
+
144
+
145
+ COSE_Key = {
146
+ 1 => tstr / int, ; kty
147
+ ? 2 => bstr, ; kid
148
+ ? 3 => tstr / int, ; alg
149
+ ? 4 => [+ (tstr / int) ], ; key_ops
150
+ ? 5 => bstr, ; Base IV
151
+ * label => values
152
+ }
153
+
154
+ COSE_KeySet = [+COSE_Key]
data/data/rfc9053.cddl ADDED
@@ -0,0 +1,21 @@
1
+
2
+ COSE_KDF_Context = [
3
+ AlgorithmID : int / tstr,
4
+ PartyUInfo : [ PartyInfo ],
5
+ PartyVInfo : [ PartyInfo ],
6
+ SuppPubInfo : [
7
+ keyDataLength : uint,
8
+ protected : empty_or_serialized_map,
9
+ ? other : bstr
10
+ ],
11
+ ? SuppPrivInfo : bstr
12
+ ]
13
+
14
+
15
+ PartyInfo = (
16
+ identity : bstr / nil,
17
+ nonce : bstr / int / nil,
18
+ other : bstr / nil
19
+ )
20
+
21
+ ;# import rfc9052
data/data/rfc9054.cddl ADDED
@@ -0,0 +1,13 @@
1
+
2
+ COSE_Hash_V = (
3
+ 1 : int / tstr, ; Algorithm identifier
4
+ 2 : bstr, ; Hash value
5
+ ? 3 : tstr, ; Location of object that was hashed
6
+ ? 4 : any ; object containing other details and things
7
+ )
8
+
9
+
10
+ COSE_Hash_Find = [
11
+ hashAlg : int / tstr,
12
+ hashValue : bstr
13
+ ]
data/data/rfc9090.cddl ADDED
@@ -0,0 +1,14 @@
1
+
2
+ ; country-rdn = {country-oid => country-value}
3
+ ; country-oid = bytes .sdnvseq [85, 4, 6]
4
+ ; country-value = text .size 2
5
+
6
+
7
+ ; country-rdn = {country-oid => country-value}
8
+ ; country-oid = bytes .oid [2, 5, 4, 6]
9
+ ; country-value = text .size 2
10
+
11
+
12
+ oid = #6.111(bstr)
13
+ roid = #6.110(bstr)
14
+ pen = #6.112(bstr)
data/data/rfc9115.cddl ADDED
@@ -0,0 +1,99 @@
1
+
2
+ csr-template-schema = {
3
+ keyTypes: [ + $keyType ]
4
+ ? subject: non-empty<distinguishedName>
5
+ extensions: extensions
6
+ }
7
+
8
+ non-empty<M> = (M) .and ({ + any => any })
9
+
10
+ mandatory-wildcard = "**"
11
+ optional-wildcard = "*"
12
+ wildcard = mandatory-wildcard / optional-wildcard
13
+
14
+ ; regtext matches all text strings but "*" and "**"
15
+ regtext = text .regexp "([^\\*].*)|([\\*][^\\*].*)|([\\*][\\*].+)"
16
+
17
+ regtext-or-wildcard = regtext / wildcard
18
+
19
+ distinguishedName = {
20
+ ? country: regtext-or-wildcard
21
+ ? stateOrProvince: regtext-or-wildcard
22
+ ? locality: regtext-or-wildcard
23
+ ? organization: regtext-or-wildcard
24
+ ? organizationalUnit: regtext-or-wildcard
25
+ ? emailAddress: regtext-or-wildcard
26
+ ? commonName: regtext-or-wildcard
27
+ }
28
+
29
+ $keyType /= rsaKeyType
30
+ $keyType /= ecdsaKeyType
31
+
32
+ rsaKeyType = {
33
+ PublicKeyType: "rsaEncryption" ; OID: 1.2.840.113549.1.1.1
34
+ PublicKeyLength: rsaKeySize
35
+ SignatureType: $rsaSignatureType
36
+ }
37
+
38
+ rsaKeySize = uint
39
+
40
+ ; RSASSA-PKCS1-v1_5 with SHA-256
41
+ $rsaSignatureType /= "sha256WithRSAEncryption"
42
+ ; RSASSA-PCKS1-v1_5 with SHA-384
43
+ $rsaSignatureType /= "sha384WithRSAEncryption"
44
+ ; RSASSA-PCKS1-v1_5 with SHA-512
45
+ $rsaSignatureType /= "sha512WithRSAEncryption"
46
+ ; RSASSA-PSS with SHA-256, MGF-1 with SHA-256, and a 32 byte salt
47
+ $rsaSignatureType /= "sha256WithRSAandMGF1"
48
+ ; RSASSA-PSS with SHA-384, MGF-1 with SHA-384, and a 48 byte salt
49
+ $rsaSignatureType /= "sha384WithRSAandMGF1"
50
+ ; RSASSA-PSS with SHA-512, MGF-1 with SHA-512, and a 64 byte salt
51
+ $rsaSignatureType /= "sha512WithRSAandMGF1"
52
+
53
+ ecdsaKeyType = {
54
+ PublicKeyType: "id-ecPublicKey" ; OID: 1.2.840.10045.2.1
55
+ namedCurve: $ecdsaCurve
56
+ SignatureType: $ecdsaSignatureType
57
+ }
58
+
59
+ $ecdsaCurve /= "secp256r1" ; OID: 1.2.840.10045.3.1.7
60
+ $ecdsaCurve /= "secp384r1" ; OID: 1.3.132.0.34
61
+ $ecdsaCurve /= "secp521r1" ; OID: 1.3.132.0.3
62
+
63
+ $ecdsaSignatureType /= "ecdsa-with-SHA256" ; paired with secp256r1
64
+ $ecdsaSignatureType /= "ecdsa-with-SHA384" ; paired with secp384r1
65
+ $ecdsaSignatureType /= "ecdsa-with-SHA512" ; paired with secp521r1
66
+
67
+ subjectaltname = {
68
+ ? DNS: [ + regtext-or-wildcard ]
69
+ ? Email: [ + regtext ]
70
+ ? URI: [ + regtext ]
71
+ * $$subjectaltname-extension
72
+ }
73
+
74
+ extensions = {
75
+ ? keyUsage: [ + keyUsageType ]
76
+ ? extendedKeyUsage: [ + extendedKeyUsageType ]
77
+ subjectAltName: non-empty<subjectaltname>
78
+ }
79
+
80
+ keyUsageType /= "digitalSignature"
81
+ keyUsageType /= "nonRepudiation"
82
+ keyUsageType /= "keyEncipherment"
83
+ keyUsageType /= "dataEncipherment"
84
+ keyUsageType /= "keyAgreement"
85
+ keyUsageType /= "keyCertSign"
86
+ keyUsageType /= "cRLSign"
87
+ keyUsageType /= "encipherOnly"
88
+ keyUsageType /= "decipherOnly"
89
+
90
+ extendedKeyUsageType /= "serverAuth"
91
+ extendedKeyUsageType /= "clientAuth"
92
+ extendedKeyUsageType /= "codeSigning"
93
+ extendedKeyUsageType /= "emailProtection"
94
+ extendedKeyUsageType /= "timeStamping"
95
+ extendedKeyUsageType /= "OCSPSigning"
96
+ extendedKeyUsageType /= oid
97
+
98
+ oid = text .regexp "([0-2])((\\.0)|(\\.[1-9][0-9]*))*"
99
+
data/data/rfc9164.cddl ADDED
@@ -0,0 +1,32 @@
1
+
2
+ ip-address-or-prefix = ipv6-address-or-prefix /
3
+ ipv4-address-or-prefix
4
+
5
+ ipv6-address-or-prefix = #6.54(ipv6-address /
6
+ ipv6-address-with-prefix /
7
+ ipv6-prefix)
8
+ ipv4-address-or-prefix = #6.52(ipv4-address /
9
+ ipv4-address-with-prefix /
10
+ ipv4-prefix)
11
+
12
+ ipv6-address = bytes .size 16
13
+ ipv4-address = bytes .size 4
14
+
15
+ ipv6-address-with-prefix = [ipv6-address,
16
+ ipv6-prefix-length / null,
17
+ ?ip-zone-identifier]
18
+ ipv4-address-with-prefix = [ipv4-address,
19
+ ipv4-prefix-length / null,
20
+ ?ip-zone-identifier]
21
+
22
+ ipv6-prefix-length = 0..128
23
+ ipv4-prefix-length = 0..32
24
+
25
+ ipv6-prefix = [ipv6-prefix-length, ipv6-prefix-bytes]
26
+ ipv4-prefix = [ipv4-prefix-length, ipv4-prefix-bytes]
27
+
28
+ ipv6-prefix-bytes = bytes .size (uint .le 16)
29
+ ipv4-prefix-bytes = bytes .size (uint .le 4)
30
+
31
+ ip-zone-identifier = uint / text
32
+
data/data/rfc9165.cddl ADDED
@@ -0,0 +1,35 @@
1
+ ; for RFC 8943
2
+ Tag1004 = #6.1004(text .abnf full-date)
3
+ ; for RFC 8949
4
+ Tag0 = #6.0(text .abnf date-time)
5
+
6
+ full-date = "full-date" .cat rfc3339
7
+ date-time = "date-time" .cat rfc3339
8
+
9
+ ; Note the trick of idiomatically starting with a newline, separating
10
+ ; off the element in the concatenations above from the rule-list
11
+ rfc3339 = '
12
+ date-fullyear = 4DIGIT
13
+ date-month = 2DIGIT ; 01-12
14
+ date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
15
+ ; month/year
16
+ time-hour = 2DIGIT ; 00-23
17
+ time-minute = 2DIGIT ; 00-59
18
+ time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap sec
19
+ ; rules
20
+ time-secfrac = "." 1*DIGIT
21
+ time-numoffset = ("+" / "-") time-hour ":" time-minute
22
+ time-offset = "Z" / time-numoffset
23
+
24
+ partial-time = time-hour ":" time-minute ":" time-second
25
+ [time-secfrac]
26
+ full-date = date-fullyear "-" date-month "-" date-mday
27
+ full-time = partial-time time-offset
28
+
29
+ date-time = full-date "T" full-time
30
+ ' .det rfc5234-core
31
+
32
+ rfc5234-core = '
33
+ DIGIT = %x30-39 ; 0-9
34
+ ; abbreviated here
35
+ '