Skip to main content

matter_cert/
error.rs

1//! Error type for `matter-cert`.
2
3use thiserror::Error;
4
5use crate::time::MatterTime;
6
7/// All errors `matter-cert` can produce.
8#[derive(Debug, Error)]
9#[non_exhaustive]
10pub enum Error {
11    /// TLV decoding or encoding failed inside `matter-codec`.
12    #[error("TLV codec error: {0}")]
13    Codec(#[from] matter_codec::Error),
14
15    /// A required certificate field was missing.
16    #[error("missing required certificate field (context tag {0})")]
17    MissingField(u8),
18
19    /// A certificate field appeared more than once.
20    #[error("duplicate certificate field (context tag {0})")]
21    DuplicateField(u8),
22
23    /// A certificate field had an unexpected element type.
24    #[error("invalid TLV element type for certificate field (context tag {0})")]
25    WrongFieldType(u8),
26
27    /// A certificate field's value was outside the spec-defined range.
28    #[error("certificate field value out of range (context tag {tag})")]
29    FieldValueOutOfRange {
30        /// Context tag of the offending field.
31        tag: u8,
32    },
33
34    /// The certificate serial number had a length outside the spec-allowed
35    /// range of 1..=20 bytes.
36    ///
37    /// The Matter operational-certificate profile (§6.5) inherits the X.509
38    /// `CertificateSerialNumber` constraint (RFC 5280 §4.1.2.2): a serial is
39    /// at most 20 octets, and a zero-length serial is not a valid INTEGER.
40    /// We reject both bounds at parse time so a malformed serial cannot
41    /// propagate into the X.509 TBS encoder or signature verification.
42    #[error("certificate serial number length {len} is outside the spec range 1..=20")]
43    InvalidSerialLength {
44        /// The offending serial-number length, in bytes.
45        len: usize,
46    },
47
48    /// Signature algorithm identifier was not `ecdsa-with-sha256` (1).
49    #[error("certificate signature algorithm {0} is not supported")]
50    UnsupportedSignatureAlgorithm(u8),
51
52    /// Public-key algorithm identifier was not `ec-public-key` (1).
53    #[error("certificate public-key algorithm {0} is not supported")]
54    UnsupportedPublicKeyAlgorithm(u8),
55
56    /// EC curve identifier was not `prime256v1` (1).
57    #[error("certificate EC curve {0} is not supported")]
58    UnsupportedEcCurve(u8),
59
60    /// Public-key bytes had wrong length.
61    #[error("public-key bytes have wrong length: expected 65, got {0}")]
62    WrongPublicKeyLength(usize),
63
64    /// Public-key bytes did not start with the uncompressed-point marker (0x04).
65    #[error("public-key bytes do not have the uncompressed-point prefix (0x04)")]
66    BadPublicKeyPrefix,
67
68    /// A required field on `MatterCertificate::builder()` was not set before
69    /// `build_unsigned()` was called.
70    #[error("builder field `{0}` was not set")]
71    MissingBuilderField(&'static str),
72
73    /// Signature bytes had wrong length.
74    #[error("signature bytes have wrong length: expected 64, got {0}")]
75    WrongSignatureLength(usize),
76
77    /// A distinguished-name attribute used a context tag not defined by the spec.
78    #[error("invalid distinguished-name attribute (tag {0})")]
79    InvalidDnAttribute(u8),
80
81    /// A distinguished-name attribute's value had the wrong TLV element type.
82    #[error("invalid TLV type for DN attribute (tag {0})")]
83    InvalidDnAttributeType(u8),
84
85    /// A key identifier had the wrong length (must be 20 bytes).
86    #[error("key identifier has wrong length: expected 20, got {0}")]
87    WrongKeyIdentifierLength(usize),
88
89    /// A Matter DN attribute had no defined X.509 OID mapping.
90    ///
91    /// Occurs when a [`crate::DnAttribute::Other`] is encountered during
92    /// X.509 conversion. We cannot invent an X.509 OID, and matter.js
93    /// wouldn't have signed against one we made up.
94    #[error("Matter DN attribute (tag {0}) has no defined X.509 OID mapping")]
95    DnAttributeHasNoX509Oid(u8),
96
97    /// A DN attribute belongs only to X.509 attestation certificates and
98    /// has no Matter operational-TLV cert encoding.
99    ///
100    /// Produced if [`crate::DnAttribute::VendorId`] or
101    /// [`crate::DnAttribute::ProductId`] is routed through the Matter TLV
102    /// writer. VID/PID identifiers live in DAC/PAI/PAA X.509 attestation
103    /// cert DNs (Matter §6.5.6.1), not in operational NOC/ICAC/RCAC TLV
104    /// certs, so there is no spec-defined TLV context tag for them.
105    #[error("DN attribute (tag {0}) is X.509-attestation-only and has no Matter TLV encoding")]
106    DnAttributeNotTlvEncodable(&'static str),
107
108    /// A DN attribute's value cannot be encoded in its X.509 ASN.1
109    /// string type.
110    ///
111    /// E.g., a `CountryName` containing non-printable bytes cannot
112    /// be encoded as `PrintableString`.
113    #[error("DN attribute value cannot be encoded as X.509 {asn1_type}: {reason}")]
114    InvalidDnAttributeForX509 {
115        /// The ASN.1 string type that the encoding attempt targeted.
116        asn1_type: &'static str,
117        /// Why the value did not fit.
118        reason: &'static str,
119    },
120
121    /// Signature verification failed.
122    ///
123    /// Reserved for M2.2; not produced by phase 1.
124    #[error("signature verification failed")]
125    SignatureVerificationFailed,
126
127    /// Test-support X.509 cert signing failed.
128    ///
129    /// Produced only by `test_support::build_x509_der` (behind the
130    /// `test-support` feature) when the supplied issuer PKCS#8 key is
131    /// malformed or `ring` rejects the signing request. Never produced by
132    /// production code paths.
133    #[error("test-support X.509 signing failed: {0}")]
134    TestX509SigningFailed(&'static str),
135
136    /// A certificate's `not_before` is in the future.
137    #[error("certificate is not yet valid (cert_index={cert_index}, not_before={not_before:?}, at={at:?})")]
138    NotYetValid {
139        /// Index of the offending cert in the chain (0 = leaf).
140        cert_index: u8,
141        /// The certificate's `not_before` timestamp.
142        not_before: MatterTime,
143        /// The time at which validation was attempted.
144        at: MatterTime,
145    },
146
147    /// A certificate's `not_after` is in the past.
148    #[error(
149        "certificate has expired (cert_index={cert_index}, not_after={not_after:?}, at={at:?})"
150    )]
151    Expired {
152        /// Index of the offending cert in the chain (0 = leaf).
153        cert_index: u8,
154        /// The certificate's `not_after` timestamp.
155        not_after: MatterTime,
156        /// The time at which validation was attempted.
157        at: MatterTime,
158    },
159
160    /// A certificate chain did not terminate at a trusted root.
161    #[error("certificate chain does not reach a trusted root")]
162    UntrustedRoot,
163
164    /// A cert's `issuer` did not match the next cert's `subject`.
165    #[error("issuer DN does not match next cert's subject DN (cert_index={cert_index})")]
166    IssuerSubjectMismatch {
167        /// Index of the cert whose `issuer` did not match (0 = leaf).
168        cert_index: u8,
169    },
170
171    /// A non-leaf certificate did not have `basic_constraints.is_ca = true`.
172    #[error("non-leaf certificate is not a CA (cert_index={cert_index})")]
173    NotACa {
174        /// Index of the non-CA intermediate (always > 0).
175        cert_index: u8,
176    },
177
178    /// Chain length exceeded a cert's `path_len_constraint`.
179    #[error("chain length exceeds path-length constraint (cert_index={cert_index})")]
180    PathLengthExceeded {
181        /// Index of the cert whose path-length constraint was violated.
182        cert_index: u8,
183    },
184
185    /// A non-leaf (CA) certificate lacked the `keyCertSign` `KeyUsage` bit.
186    ///
187    /// RFC 5280 §4.2.1.3 and Matter §6.5.5 require any certificate that
188    /// signs other certificates to carry the `keyCertSign` `KeyUsage` bit
189    /// (and a `KeyUsage` extension at all). A cert asserting `is_ca = true`
190    /// but lacking `KeyUsage::KEY_CERT_SIGN` (or with no `KeyUsage` extension)
191    /// is not a valid signing CA and is rejected here.
192    #[error("CA certificate lacks the keyCertSign KeyUsage bit (cert_index={cert_index})")]
193    MissingKeyCertSign {
194        /// Index of the offending CA cert in the chain (always > 0).
195        cert_index: u8,
196    },
197
198    /// The end-entity leaf certificate asserted `basic_constraints.is_ca = true`.
199    ///
200    /// RFC 5280 forbids an end-entity (leaf) certificate from asserting the
201    /// CA bit. A leaf at chain index 0 with an explicit `is_ca = true` is a
202    /// profile violation and is rejected. An absent `basic_constraints`
203    /// extension on the leaf is permitted (it is not a violation).
204    #[error("end-entity leaf certificate asserts is_ca=true (cert_index=0)")]
205    LeafIsCa,
206}
207
208/// `Result<T, Error>` for convenience.
209pub type Result<T> = core::result::Result<T, Error>;