/src/connectedhomeip/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2021-2022 Project CHIP Authors |
4 | | * |
5 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | * you may not use this file except in compliance with the License. |
7 | | * You may obtain a copy of the License at |
8 | | * |
9 | | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | | * |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | #include "DefaultDeviceAttestationVerifier.h" |
18 | | |
19 | | #include <controller/OperationalCredentialsDelegate.h> |
20 | | #include <credentials/CHIPCert.h> |
21 | | #include <credentials/CertificationDeclaration.h> |
22 | | #include <credentials/DeviceAttestationConstructor.h> |
23 | | #include <credentials/DeviceAttestationVendorReserved.h> |
24 | | #include <credentials/attestation_verifier/TestPAAStore.h> |
25 | | #include <crypto/CHIPCryptoPAL.h> |
26 | | |
27 | | #include <lib/asn1/ASN1.h> |
28 | | #include <lib/core/CHIPError.h> |
29 | | #include <lib/core/Global.h> |
30 | | #include <lib/support/CodeUtils.h> |
31 | | #include <lib/support/ScopedMemoryBuffer.h> |
32 | | #include <lib/support/Span.h> |
33 | | #include <lib/support/StringBuilder.h> |
34 | | #include <lib/support/logging/CHIPLogging.h> |
35 | | |
36 | | using namespace chip::Crypto; |
37 | | using chip::TestCerts::GetTestPaaRootStore; |
38 | | |
39 | | namespace chip { |
40 | | namespace Credentials { |
41 | | |
42 | | namespace { |
43 | | |
44 | | // As per specifications section 11.22.5.1. Constant RESP_MAX |
45 | | constexpr size_t kMaxResponseLength = 900; |
46 | | |
47 | | // Test CD Signing Key from `credentials/test/certification-declaration/Chip-Test-CD-Signing-Cert.pem` |
48 | | // used to verify any in-SDK development CDs. The associated keypair to do actual signing is in |
49 | | // `credentials/test/certification-declaration/Chip-Test-CD-Signing-Key.pem`. |
50 | | // |
51 | | // Note that this certificate is a self signed certificate and doesn't chain up to the CSA trusted root. |
52 | | // This CD Signing certificate can only be used to sign CDs for testing/development purposes |
53 | | // and should never be used in production devices. |
54 | | // |
55 | | // -----BEGIN CERTIFICATE----- |
56 | | // MIIBszCCAVqgAwIBAgIIRdrzneR6oI8wCgYIKoZIzj0EAwIwKzEpMCcGA1UEAwwg |
57 | | // TWF0dGVyIFRlc3QgQ0QgU2lnbmluZyBBdXRob3JpdHkwIBcNMjEwNjI4MTQyMzQz |
58 | | // WhgPOTk5OTEyMzEyMzU5NTlaMCsxKTAnBgNVBAMMIE1hdHRlciBUZXN0IENEIFNp |
59 | | // Z25pbmcgQXV0aG9yaXR5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPDmJIkUr |
60 | | // VcrzicJb0bykZWlSzLkOiGkkmthHRlMBTL+V1oeWXgNrUhxRA35rjO3vyh60QEZp |
61 | | // T6CIgu7WUZ3suqNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMC |
62 | | // AQYwHQYDVR0OBBYEFGL6gjNZrPqplj4c+hQK3fUE83FgMB8GA1UdIwQYMBaAFGL6 |
63 | | // gjNZrPqplj4c+hQK3fUE83FgMAoGCCqGSM49BAMCA0cAMEQCICxUXOTkV9im8NnZ |
64 | | // u+vW7OHd/n+MbZps83UyH8b6xxOEAiBUB3jodDlyUn7t669YaGIgtUB48s1OYqdq |
65 | | // 58u5L/VMiw== |
66 | | // -----END CERTIFICATE----- |
67 | | // |
68 | | constexpr uint8_t gTestCdPubkeyBytes[] = { |
69 | | 0x04, 0x3c, 0x39, 0x89, 0x22, 0x45, 0x2b, 0x55, 0xca, 0xf3, 0x89, 0xc2, 0x5b, 0xd1, 0xbc, 0xa4, 0x65, |
70 | | 0x69, 0x52, 0xcc, 0xb9, 0x0e, 0x88, 0x69, 0x24, 0x9a, 0xd8, 0x47, 0x46, 0x53, 0x01, 0x4c, 0xbf, 0x95, |
71 | | 0xd6, 0x87, 0x96, 0x5e, 0x03, 0x6b, 0x52, 0x1c, 0x51, 0x03, 0x7e, 0x6b, 0x8c, 0xed, 0xef, 0xca, 0x1e, |
72 | | 0xb4, 0x40, 0x46, 0x69, 0x4f, 0xa0, 0x88, 0x82, 0xee, 0xd6, 0x51, 0x9d, 0xec, 0xba, |
73 | | }; |
74 | | |
75 | | constexpr uint8_t gTestCdPubkeyKid[] = { |
76 | | 0x62, 0xfa, 0x82, 0x33, 0x59, 0xac, 0xfa, 0xa9, 0x96, 0x3e, 0x1c, 0xfa, 0x14, 0x0a, 0xdd, 0xf5, 0x04, 0xf3, 0x71, 0x60, |
77 | | }; |
78 | | |
79 | | // Official CSA "Matter Certification and Testing CA" |
80 | | // |
81 | | // -----BEGIN CERTIFICATE----- |
82 | | // MIICATCCAaegAwIBAgIHY3Nhcm9vdDAKBggqhkjOPQQDAjBSMQwwCgYDVQQKDAND |
83 | | // U0ExLDAqBgNVBAMMI01hdHRlciBDZXJ0aWZpY2F0aW9uIGFuZCBUZXN0aW5nIENB |
84 | | // MRQwEgYKKwYBBAGConwCAQwEQzVBMDAgFw0yMjA3MDcxOTI4MDRaGA8yMTIyMDYx |
85 | | // MzE5MjgwNFowUjEMMAoGA1UECgwDQ1NBMSwwKgYDVQQDDCNNYXR0ZXIgQ2VydGlm |
86 | | // aWNhdGlvbiBhbmQgVGVzdGluZyBDQTEUMBIGCisGAQQBgqJ8AgEMBEM1QTAwWTAT |
87 | | // BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ4SjrDql2+y3IP5iEdPK1IYm/3EaCkkp+t |
88 | | // 2GD44nf/wN4fPrYzejSEe1o6BW6ocQ6Td+7t7iUXA/3ZNQEly45Io2YwZDASBgNV |
89 | | // HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUl+Rp0MUE |
90 | | // FMJvxwH3fpR3OQmN9qUwHwYDVR0jBBgwFoAUl+Rp0MUEFMJvxwH3fpR3OQmN9qUw |
91 | | // CgYIKoZIzj0EAwIDSAAwRQIgearlB0fCJ49UoJ6xwKPdlPEopCOL9jVCviODEleI |
92 | | // +mQCIQDvvDCKi7kvj4R4BoFS4BVZGCk4zJ84W4tfTTfu89lRbQ== |
93 | | // -----END CERTIFICATE----- |
94 | | // |
95 | | constexpr uint8_t gCdRootCert[] = { |
96 | | 0x30, 0x82, 0x02, 0x01, 0x30, 0x82, 0x01, 0xa7, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x07, 0x63, 0x73, 0x61, 0x72, 0x6f, 0x6f, |
97 | | 0x74, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x52, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, |
98 | | 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x43, 0x53, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x23, 0x4d, 0x61, |
99 | | 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, |
100 | | 0x64, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x41, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, |
101 | | 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x43, 0x35, 0x41, 0x30, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x37, |
102 | | 0x30, 0x37, 0x31, 0x39, 0x32, 0x38, 0x30, 0x34, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32, 0x32, 0x30, 0x36, 0x31, 0x33, 0x31, 0x39, |
103 | | 0x32, 0x38, 0x30, 0x34, 0x5a, 0x30, 0x52, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x43, 0x53, 0x41, |
104 | | 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x23, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, |
105 | | 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, |
106 | | 0x67, 0x20, 0x43, 0x41, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, |
107 | | 0x04, 0x43, 0x35, 0x41, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, |
108 | | 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x38, 0x4a, 0x3a, 0xc3, 0xaa, 0x5d, 0xbe, 0xcb, 0x72, 0x0f, |
109 | | 0xe6, 0x21, 0x1d, 0x3c, 0xad, 0x48, 0x62, 0x6f, 0xf7, 0x11, 0xa0, 0xa4, 0x92, 0x9f, 0xad, 0xd8, 0x60, 0xf8, 0xe2, 0x77, 0xff, |
110 | | 0xc0, 0xde, 0x1f, 0x3e, 0xb6, 0x33, 0x7a, 0x34, 0x84, 0x7b, 0x5a, 0x3a, 0x05, 0x6e, 0xa8, 0x71, 0x0e, 0x93, 0x77, 0xee, 0xed, |
111 | | 0xee, 0x25, 0x17, 0x03, 0xfd, 0xd9, 0x35, 0x01, 0x25, 0xcb, 0x8e, 0x48, 0xa3, 0x66, 0x30, 0x64, 0x30, 0x12, 0x06, 0x03, 0x55, |
112 | | 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, |
113 | | 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, |
114 | | 0x97, 0xe4, 0x69, 0xd0, 0xc5, 0x04, 0x14, 0xc2, 0x6f, 0xc7, 0x01, 0xf7, 0x7e, 0x94, 0x77, 0x39, 0x09, 0x8d, 0xf6, 0xa5, 0x30, |
115 | | 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x97, 0xe4, 0x69, 0xd0, 0xc5, 0x04, 0x14, 0xc2, 0x6f, |
116 | | 0xc7, 0x01, 0xf7, 0x7e, 0x94, 0x77, 0x39, 0x09, 0x8d, 0xf6, 0xa5, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, |
117 | | 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x79, 0xaa, 0xe5, 0x07, 0x47, 0xc2, 0x27, 0x8f, 0x54, 0xa0, 0x9e, 0xb1, |
118 | | 0xc0, 0xa3, 0xdd, 0x94, 0xf1, 0x28, 0xa4, 0x23, 0x8b, 0xf6, 0x35, 0x42, 0xbe, 0x23, 0x83, 0x12, 0x57, 0x88, 0xfa, 0x64, 0x02, |
119 | | 0x21, 0x00, 0xef, 0xbc, 0x30, 0x8a, 0x8b, 0xb9, 0x2f, 0x8f, 0x84, 0x78, 0x06, 0x81, 0x52, 0xe0, 0x15, 0x59, 0x18, 0x29, 0x38, |
120 | | 0xcc, 0x9f, 0x38, 0x5b, 0x8b, 0x5f, 0x4d, 0x37, 0xee, 0xf3, 0xd9, 0x51, 0x6d |
121 | | }; |
122 | | |
123 | | // Official CD "Signing Key 001" |
124 | | // |
125 | | // -----BEGIN CERTIFICATE----- |
126 | | // MIICBzCCAa2gAwIBAgIHY3NhY2RrMTAKBggqhkjOPQQDAjBSMQwwCgYDVQQKDAND |
127 | | // U0ExLDAqBgNVBAMMI01hdHRlciBDZXJ0aWZpY2F0aW9uIGFuZCBUZXN0aW5nIENB |
128 | | // MRQwEgYKKwYBBAGConwCAQwEQzVBMDAgFw0yMjEwMDMxOTI4NTVaGA8yMDcyMDky |
129 | | // MDE5Mjg1NVowWDEMMAoGA1UECgwDQ1NBMTIwMAYDVQQDDClDZXJ0aWZpY2F0aW9u |
130 | | // IERlY2xhcmF0aW9uIFNpZ25pbmcgS2V5IDAwMTEUMBIGCisGAQQBgqJ8AgEMBEM1 |
131 | | // QTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATN7uk+RPi3K+PRqcB+IZaLmv/z |
132 | | // tAPwXhZp17Hlyu5vx3FLQufiNpXpLNdjVHOigK5ojze7lInhFim5uU/3sJkpo2Yw |
133 | | // ZDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU |
134 | | // /jQ/lZlHdjth7kU5ExM4SU/mfY4wHwYDVR0jBBgwFoAUl+Rp0MUEFMJvxwH3fpR3 |
135 | | // OQmN9qUwCgYIKoZIzj0EAwIDSAAwRQIgEDWOcdKsVGtUh3evHbBd1lq4aS7yQtOp |
136 | | // 6GrOQ3/zXBsCIQDxorh2RXSaI8m2RCcoWaiWa0nLzQepNm3C2jrQVJmC2Q== |
137 | | // -----END CERTIFICATE----- |
138 | | // |
139 | | constexpr uint8_t gCdSigningKey001PubkeyBytes[] = { |
140 | | 0x04, 0xcd, 0xee, 0xe9, 0x3e, 0x44, 0xf8, 0xb7, 0x2b, 0xe3, 0xd1, 0xa9, 0xc0, 0x7e, 0x21, 0x96, 0x8b, |
141 | | 0x9a, 0xff, 0xf3, 0xb4, 0x03, 0xf0, 0x5e, 0x16, 0x69, 0xd7, 0xb1, 0xe5, 0xca, 0xee, 0x6f, 0xc7, 0x71, |
142 | | 0x4b, 0x42, 0xe7, 0xe2, 0x36, 0x95, 0xe9, 0x2c, 0xd7, 0x63, 0x54, 0x73, 0xa2, 0x80, 0xae, 0x68, 0x8f, |
143 | | 0x37, 0xbb, 0x94, 0x89, 0xe1, 0x16, 0x29, 0xb9, 0xb9, 0x4f, 0xf7, 0xb0, 0x99, 0x29, |
144 | | }; |
145 | | |
146 | | constexpr uint8_t gCdSigningKey001Kid[] = { |
147 | | 0xFE, 0x34, 0x3F, 0x95, 0x99, 0x47, 0x76, 0x3B, 0x61, 0xEE, 0x45, 0x39, 0x13, 0x13, 0x38, 0x49, 0x4F, 0xE6, 0x7D, 0x8E, |
148 | | }; |
149 | | |
150 | | // Official CD "Signing Key 002" |
151 | | // |
152 | | // -----BEGIN CERTIFICATE----- |
153 | | // MIICCDCCAa2gAwIBAgIHY3NhY2RrMjAKBggqhkjOPQQDAjBSMQwwCgYDVQQKDAND |
154 | | // U0ExLDAqBgNVBAMMI01hdHRlciBDZXJ0aWZpY2F0aW9uIGFuZCBUZXN0aW5nIENB |
155 | | // MRQwEgYKKwYBBAGConwCAQwEQzVBMDAgFw0yMjEwMDMxOTM2NDZaGA8yMDcyMDky |
156 | | // MDE5MzY0NlowWDEMMAoGA1UECgwDQ1NBMTIwMAYDVQQDDClDZXJ0aWZpY2F0aW9u |
157 | | // IERlY2xhcmF0aW9uIFNpZ25pbmcgS2V5IDAwMjEUMBIGCisGAQQBgqJ8AgEMBEM1 |
158 | | // QTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQDGTfo+UJRBF3ydFe7RiU+43VO |
159 | | // jBKuKFV9gCe51MNW2RtAjP8yJ1AXsl+Mi6IFFtXIOvK3JBKAE9/Mj5XSAKkLo2Yw |
160 | | // ZDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU |
161 | | // 3QTbWFshTBxYFYfmVo30h7bdxwEwHwYDVR0jBBgwFoAUl+Rp0MUEFMJvxwH3fpR3 |
162 | | // OQmN9qUwCgYIKoZIzj0EAwIDSQAwRgIhAJruzxZ806cP/LoQ07PN9xAbjLdwUalV |
163 | | // h0Qfx304Tb92AiEAk+jnf2qtyfKyTEHpT3Xf3bfekqUOA+8ikB1yjL5oTsI= |
164 | | // -----END CERTIFICATE----- |
165 | | // |
166 | | constexpr uint8_t gCdSigningKey002PubkeyBytes[] = { |
167 | | 0x04, 0x03, 0x19, 0x37, 0xe8, 0xf9, 0x42, 0x51, 0x04, 0x5d, 0xf2, 0x74, 0x57, 0xbb, 0x46, 0x25, 0x3e, |
168 | | 0xe3, 0x75, 0x4e, 0x8c, 0x12, 0xae, 0x28, 0x55, 0x7d, 0x80, 0x27, 0xb9, 0xd4, 0xc3, 0x56, 0xd9, 0x1b, |
169 | | 0x40, 0x8c, 0xff, 0x32, 0x27, 0x50, 0x17, 0xb2, 0x5f, 0x8c, 0x8b, 0xa2, 0x05, 0x16, 0xd5, 0xc8, 0x3a, |
170 | | 0xf2, 0xb7, 0x24, 0x12, 0x80, 0x13, 0xdf, 0xcc, 0x8f, 0x95, 0xd2, 0x00, 0xa9, 0x0b, |
171 | | }; |
172 | | |
173 | | constexpr uint8_t gCdSigningKey002Kid[] = { |
174 | | 0xDD, 0x04, 0xDB, 0x58, 0x5B, 0x21, 0x4C, 0x1C, 0x58, 0x15, 0x87, 0xE6, 0x56, 0x8D, 0xF4, 0x87, 0xB6, 0xDD, 0xC7, 0x01, |
175 | | }; |
176 | | |
177 | | // Official CD "Signing Key 003" |
178 | | // |
179 | | // -----BEGIN CERTIFICATE----- |
180 | | // MIICBjCCAa2gAwIBAgIHY3NhY2RrMzAKBggqhkjOPQQDAjBSMQwwCgYDVQQKDAND |
181 | | // U0ExLDAqBgNVBAMMI01hdHRlciBDZXJ0aWZpY2F0aW9uIGFuZCBUZXN0aW5nIENB |
182 | | // MRQwEgYKKwYBBAGConwCAQwEQzVBMDAgFw0yMjEwMDMxOTQxMDFaGA8yMDcyMDky |
183 | | // MDE5NDEwMVowWDEMMAoGA1UECgwDQ1NBMTIwMAYDVQQDDClDZXJ0aWZpY2F0aW9u |
184 | | // IERlY2xhcmF0aW9uIFNpZ25pbmcgS2V5IDAwMzEUMBIGCisGAQQBgqJ8AgEMBEM1 |
185 | | // QTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASfV1zV/bdSHxCk3zHwc5ErYUco |
186 | | // 8tN/W2uWvCy/fAsRlpBXfVVdIaCWYKiwgqM56lMPeoEthpO1b9dkGF+rzTL1o2Yw |
187 | | // ZDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU |
188 | | // RxA158BOqqi+fE1ME+PkwgmVqEswHwYDVR0jBBgwFoAUl+Rp0MUEFMJvxwH3fpR3 |
189 | | // OQmN9qUwCgYIKoZIzj0EAwIDRwAwRAIgIFecbY+1mVVNqxH9+8IMB8+safdyIJU2 |
190 | | // AqqtZ/w7AkQCIHiVlYTaCnJsnW5/cvj9GfIv7Eb0cjdmcAkrYGbnPQzX |
191 | | // -----END CERTIFICATE----- |
192 | | // |
193 | | constexpr uint8_t gCdSigningKey003PubkeyBytes[] = { |
194 | | 0x04, 0x9f, 0x57, 0x5c, 0xd5, 0xfd, 0xb7, 0x52, 0x1f, 0x10, 0xa4, 0xdf, 0x31, 0xf0, 0x73, 0x91, 0x2b, |
195 | | 0x61, 0x47, 0x28, 0xf2, 0xd3, 0x7f, 0x5b, 0x6b, 0x96, 0xbc, 0x2c, 0xbf, 0x7c, 0x0b, 0x11, 0x96, 0x90, |
196 | | 0x57, 0x7d, 0x55, 0x5d, 0x21, 0xa0, 0x96, 0x60, 0xa8, 0xb0, 0x82, 0xa3, 0x39, 0xea, 0x53, 0x0f, 0x7a, |
197 | | 0x81, 0x2d, 0x86, 0x93, 0xb5, 0x6f, 0xd7, 0x64, 0x18, 0x5f, 0xab, 0xcd, 0x32, 0xf5, |
198 | | }; |
199 | | |
200 | | constexpr uint8_t gCdSigningKey003Kid[] = { |
201 | | 0x47, 0x10, 0x35, 0xE7, 0xC0, 0x4E, 0xAA, 0xA8, 0xBE, 0x7C, 0x4D, 0x4C, 0x13, 0xE3, 0xE4, 0xC2, 0x09, 0x95, 0xA8, 0x4B, |
202 | | }; |
203 | | |
204 | | // Official CD "Signing Key 004" |
205 | | // |
206 | | // -----BEGIN CERTIFICATE----- |
207 | | // MIICBjCCAa2gAwIBAgIHY3NhY2RrNDAKBggqhkjOPQQDAjBSMQwwCgYDVQQKDAND |
208 | | // U0ExLDAqBgNVBAMMI01hdHRlciBDZXJ0aWZpY2F0aW9uIGFuZCBUZXN0aW5nIENB |
209 | | // MRQwEgYKKwYBBAGConwCAQwEQzVBMDAgFw0yMjEwMDMxOTQzMjFaGA8yMDcyMDky |
210 | | // MDE5NDMyMVowWDEMMAoGA1UECgwDQ1NBMTIwMAYDVQQDDClDZXJ0aWZpY2F0aW9u |
211 | | // IERlY2xhcmF0aW9uIFNpZ25pbmcgS2V5IDAwNDEUMBIGCisGAQQBgqJ8AgEMBEM1 |
212 | | // QTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR8/I2IEKic9PoZF3jyr+x4+FF6 |
213 | | // l6Plf8ITutiI42EedP+2hL3rqKaLJSNKXDWPNzurm20wThMG3XYgpSjRFhwLo2Yw |
214 | | // ZDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU |
215 | | // 9oYDo2kumBByQZ6h4as4VL13ldMwHwYDVR0jBBgwFoAUl+Rp0MUEFMJvxwH3fpR3 |
216 | | // OQmN9qUwCgYIKoZIzj0EAwIDRwAwRAIgLqAfkbtLYYdmQsnbn0CWv3G1/lbE36nz |
217 | | // HbLbW5t6PY4CIE8oyIHsVhNSTPcb3mwRp+Vxhs8tKhbAdwv5BGgDaAHj |
218 | | // -----END CERTIFICATE----- |
219 | | // |
220 | | constexpr uint8_t gCdSigningKey004PubkeyBytes[] = { |
221 | | 0x04, 0x7c, 0xfc, 0x8d, 0x88, 0x10, 0xa8, 0x9c, 0xf4, 0xfa, 0x19, 0x17, 0x78, 0xf2, 0xaf, 0xec, 0x78, |
222 | | 0xf8, 0x51, 0x7a, 0x97, 0xa3, 0xe5, 0x7f, 0xc2, 0x13, 0xba, 0xd8, 0x88, 0xe3, 0x61, 0x1e, 0x74, 0xff, |
223 | | 0xb6, 0x84, 0xbd, 0xeb, 0xa8, 0xa6, 0x8b, 0x25, 0x23, 0x4a, 0x5c, 0x35, 0x8f, 0x37, 0x3b, 0xab, 0x9b, |
224 | | 0x6d, 0x30, 0x4e, 0x13, 0x06, 0xdd, 0x76, 0x20, 0xa5, 0x28, 0xd1, 0x16, 0x1c, 0x0b, |
225 | | }; |
226 | | |
227 | | constexpr uint8_t gCdSigningKey004Kid[] = { |
228 | | 0xF6, 0x86, 0x03, 0xA3, 0x69, 0x2E, 0x98, 0x10, 0x72, 0x41, 0x9E, 0xA1, 0xE1, 0xAB, 0x38, 0x54, 0xBD, 0x77, 0x95, 0xD3, |
229 | | }; |
230 | | |
231 | | // Official CD "Signing Key 005" |
232 | | // |
233 | | // -----BEGIN CERTIFICATE----- |
234 | | // MIICBzCCAa2gAwIBAgIHY3NhY2RrNTAKBggqhkjOPQQDAjBSMQwwCgYDVQQKDAND |
235 | | // U0ExLDAqBgNVBAMMI01hdHRlciBDZXJ0aWZpY2F0aW9uIGFuZCBUZXN0aW5nIENB |
236 | | // MRQwEgYKKwYBBAGConwCAQwEQzVBMDAgFw0yMjEwMDMxOTQ3MTVaGA8yMDcyMDky |
237 | | // MDE5NDcxNVowWDEMMAoGA1UECgwDQ1NBMTIwMAYDVQQDDClDZXJ0aWZpY2F0aW9u |
238 | | // IERlY2xhcmF0aW9uIFNpZ25pbmcgS2V5IDAwNTEUMBIGCisGAQQBgqJ8AgEMBEM1 |
239 | | // QTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARDilLGYqKm1yZH+V63UxNu5K4P |
240 | | // 2zqpwWkxQms9CGf5EDrn16G4h+n4E6byb3a7zak1k3h8EneMqPKXXcRaIEL5o2Yw |
241 | | // ZDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQU |
242 | | // Y38mNK1i6v5q9mLvuW9v0vy//C8wHwYDVR0jBBgwFoAUl+Rp0MUEFMJvxwH3fpR3 |
243 | | // OQmN9qUwCgYIKoZIzj0EAwIDSAAwRQIhAM1HQpvkHKxLJByWaSYAPRZgh3Bis18W |
244 | | // AViq7c/mtzEAAiBZO0lVe6Qo9iQPIBWZaVx/S/YSNO9uKNa/pvFu3V+nIg== |
245 | | // -----END CERTIFICATE----- |
246 | | // |
247 | | constexpr uint8_t gCdSigningKey005PubkeyBytes[] = { |
248 | | 0x04, 0x43, 0x8a, 0x52, 0xc6, 0x62, 0xa2, 0xa6, 0xd7, 0x26, 0x47, 0xf9, 0x5e, 0xb7, 0x53, 0x13, 0x6e, |
249 | | 0xe4, 0xae, 0x0f, 0xdb, 0x3a, 0xa9, 0xc1, 0x69, 0x31, 0x42, 0x6b, 0x3d, 0x08, 0x67, 0xf9, 0x10, 0x3a, |
250 | | 0xe7, 0xd7, 0xa1, 0xb8, 0x87, 0xe9, 0xf8, 0x13, 0xa6, 0xf2, 0x6f, 0x76, 0xbb, 0xcd, 0xa9, 0x35, 0x93, |
251 | | 0x78, 0x7c, 0x12, 0x77, 0x8c, 0xa8, 0xf2, 0x97, 0x5d, 0xc4, 0x5a, 0x20, 0x42, 0xf9, |
252 | | }; |
253 | | |
254 | | constexpr uint8_t gCdSigningKey005Kid[] = { |
255 | | 0x63, 0x7F, 0x26, 0x34, 0xAD, 0x62, 0xEA, 0xFE, 0x6A, 0xF6, 0x62, 0xEF, 0xB9, 0x6F, 0x6F, 0xD2, 0xFC, 0xBF, 0xFC, 0x2F, |
256 | | }; |
257 | | |
258 | | struct MatterCDSigningKey |
259 | | { |
260 | | const CertificateKeyId mKid; |
261 | | const P256PublicKeySpan mPubkey; |
262 | | }; |
263 | | |
264 | | constexpr std::array<MatterCDSigningKey, 6> gCdSigningKeys = { { |
265 | | { FixedByteSpan<20>{ gTestCdPubkeyKid }, FixedByteSpan<65>{ gTestCdPubkeyBytes } }, |
266 | | { FixedByteSpan<20>{ gCdSigningKey001Kid }, FixedByteSpan<65>{ gCdSigningKey001PubkeyBytes } }, |
267 | | { FixedByteSpan<20>{ gCdSigningKey002Kid }, FixedByteSpan<65>{ gCdSigningKey002PubkeyBytes } }, |
268 | | { FixedByteSpan<20>{ gCdSigningKey003Kid }, FixedByteSpan<65>{ gCdSigningKey003PubkeyBytes } }, |
269 | | { FixedByteSpan<20>{ gCdSigningKey004Kid }, FixedByteSpan<65>{ gCdSigningKey004PubkeyBytes } }, |
270 | | { FixedByteSpan<20>{ gCdSigningKey005Kid }, FixedByteSpan<65>{ gCdSigningKey005PubkeyBytes } }, |
271 | | } }; |
272 | | |
273 | | struct TestAttestationTrustStore final : public ArrayAttestationTrustStore |
274 | | { |
275 | 0 | TestAttestationTrustStore() : ArrayAttestationTrustStore(GetTestPaaRootStore().data(), GetTestPaaRootStore().size()) {} |
276 | | }; |
277 | | Global<TestAttestationTrustStore> gTestAttestationTrustStore; |
278 | | |
279 | | AttestationVerificationResult MapError(CertificateChainValidationResult certificateChainValidationResult) |
280 | 0 | { |
281 | 0 | switch (certificateChainValidationResult) |
282 | 0 | { |
283 | 0 | case CertificateChainValidationResult::kRootFormatInvalid: |
284 | 0 | return AttestationVerificationResult::kPaaFormatInvalid; |
285 | | |
286 | 0 | case CertificateChainValidationResult::kRootArgumentInvalid: |
287 | 0 | return AttestationVerificationResult::kPaaArgumentInvalid; |
288 | | |
289 | 0 | case CertificateChainValidationResult::kICAFormatInvalid: |
290 | 0 | return AttestationVerificationResult::kPaiFormatInvalid; |
291 | | |
292 | 0 | case CertificateChainValidationResult::kICAArgumentInvalid: |
293 | 0 | return AttestationVerificationResult::kPaiArgumentInvalid; |
294 | | |
295 | 0 | case CertificateChainValidationResult::kLeafFormatInvalid: |
296 | 0 | return AttestationVerificationResult::kDacFormatInvalid; |
297 | | |
298 | 0 | case CertificateChainValidationResult::kLeafArgumentInvalid: |
299 | 0 | return AttestationVerificationResult::kDacArgumentInvalid; |
300 | | |
301 | 0 | case CertificateChainValidationResult::kChainInvalid: |
302 | 0 | return AttestationVerificationResult::kDacSignatureInvalid; |
303 | | |
304 | 0 | case CertificateChainValidationResult::kNoMemory: |
305 | 0 | return AttestationVerificationResult::kNoMemory; |
306 | | |
307 | 0 | case CertificateChainValidationResult::kInternalFrameworkError: |
308 | 0 | return AttestationVerificationResult::kInternalError; |
309 | | |
310 | 0 | default: |
311 | 0 | return AttestationVerificationResult::kInternalError; |
312 | 0 | } |
313 | 0 | } |
314 | | |
315 | | bool SupportsAttestationVerificationProfile(DeviceAttestationCertProfile profile) |
316 | 0 | { |
317 | 0 | switch (profile) |
318 | 0 | { |
319 | 0 | case DeviceAttestationCertProfile::kEcdsaMatterLegacy: |
320 | 0 | return true; |
321 | 0 | case DeviceAttestationCertProfile::kMlDsa44: |
322 | 0 | return Crypto::IsMlDsa44Supported(); |
323 | 0 | case DeviceAttestationCertProfile::kMlDsa65: |
324 | 0 | return Crypto::IsMlDsa65Supported(); |
325 | 0 | case DeviceAttestationCertProfile::kUnknownEnumValue: |
326 | 0 | return false; |
327 | 0 | } |
328 | | |
329 | 0 | return false; |
330 | 0 | } |
331 | | |
332 | | // CertificateType class doesn't work since it doesn't encode PAA. |
333 | | enum class AttestationChainElement : uint8_t |
334 | | { |
335 | | kPAA = 0, |
336 | | kPAI = 1, |
337 | | kDAC = 2 |
338 | | }; |
339 | | |
340 | | enum class KeyIdType : uint8_t |
341 | | { |
342 | | kAuthorityKeyId = 0, |
343 | | kSubjectKeyId = 1, |
344 | | }; |
345 | | |
346 | | #if CHIP_PROGRESS_LOGGING |
347 | | const char * CertTypeAsString(AttestationChainElement certType) |
348 | 0 | { |
349 | 0 | switch (certType) |
350 | 0 | { |
351 | 0 | case AttestationChainElement::kPAA: |
352 | 0 | return "PAA"; |
353 | 0 | case AttestationChainElement::kPAI: |
354 | 0 | return "PAI"; |
355 | 0 | case AttestationChainElement::kDAC: |
356 | 0 | return "DAC"; |
357 | 0 | default: |
358 | 0 | break; |
359 | 0 | } |
360 | 0 | return "<UNKNOWN>"; |
361 | 0 | } |
362 | | #endif // CHIP_PROGRESS_LOGGING |
363 | | |
364 | | void LogOneKeyId(KeyIdType keyIdType, AttestationChainElement certType, ByteSpan derBuffer) |
365 | 0 | { |
366 | 0 | #if CHIP_PROGRESS_LOGGING |
367 | 0 | const char * certTypeName = CertTypeAsString(certType); |
368 | |
|
369 | 0 | uint8_t keyIdBuf[Crypto::kAuthorityKeyIdentifierLength]; // Big enough for SKID/AKID. |
370 | 0 | MutableByteSpan keyIdSpan{ keyIdBuf }; |
371 | 0 | CHIP_ERROR err = CHIP_NO_ERROR; |
372 | |
|
373 | 0 | const char * keyIdTypeString = "<UNKNOWN>"; |
374 | 0 | switch (keyIdType) |
375 | 0 | { |
376 | 0 | case KeyIdType::kAuthorityKeyId: |
377 | 0 | err = ExtractAKIDFromX509Cert(derBuffer, keyIdSpan); |
378 | 0 | keyIdTypeString = "AKID"; |
379 | 0 | break; |
380 | 0 | case KeyIdType::kSubjectKeyId: |
381 | 0 | err = ExtractSKIDFromX509Cert(derBuffer, keyIdSpan); |
382 | 0 | keyIdTypeString = "SKID"; |
383 | 0 | break; |
384 | 0 | default: |
385 | 0 | err = CHIP_ERROR_INTERNAL; |
386 | 0 | break; |
387 | 0 | } |
388 | | |
389 | 0 | if (err != CHIP_NO_ERROR) |
390 | 0 | { |
391 | 0 | ChipLogError(NotSpecified, "Failed to extract %s from %s: %" CHIP_ERROR_FORMAT, keyIdTypeString, certTypeName, |
392 | 0 | err.Format()); |
393 | 0 | return; |
394 | 0 | } |
395 | | |
396 | 0 | KeyIdStringifier KeyIdStringifier; |
397 | 0 | const char * keyIdString = KeyIdStringifier.KeyIdToHex(keyIdSpan); |
398 | |
|
399 | 0 | ChipLogProgress(NotSpecified, "--> %s certificate %s: %s", certTypeName, keyIdTypeString, keyIdString); |
400 | | #else |
401 | | IgnoreUnusedVariable(keyIdType); |
402 | | IgnoreUnusedVariable(certType); |
403 | | IgnoreUnusedVariable(derBuffer); |
404 | | #endif // CHIP_PROGRESS_LOGGING |
405 | 0 | } |
406 | | |
407 | | void LogCertificateAsPem(AttestationChainElement element, ByteSpan derBuffer) |
408 | 0 | { |
409 | 0 | #if CHIP_PROGRESS_LOGGING |
410 | 0 | ChipLogProgress(NotSpecified, "==== %s certificate considered (%u bytes) ====", CertTypeAsString(element), |
411 | 0 | static_cast<unsigned>(derBuffer.size())); |
412 | 0 | PemEncoder encoder("CERTIFICATE", derBuffer); |
413 | 0 | for (const char * pemLine = encoder.NextLine(); pemLine != nullptr; pemLine = encoder.NextLine()) |
414 | 0 | { |
415 | 0 | ChipLogProgress(NotSpecified, "%s", pemLine); |
416 | 0 | } |
417 | | #else |
418 | | IgnoreUnusedVariable(element); |
419 | | IgnoreUnusedVariable(derBuffer); |
420 | | #endif // CHIP_PROGRESS_LOGGING |
421 | 0 | } |
422 | | |
423 | | void LogCertDebugData(AttestationChainElement element, ByteSpan derBuffer) |
424 | 0 | { |
425 | 0 | LogCertificateAsPem(element, derBuffer); |
426 | 0 | LogOneKeyId(KeyIdType::kSubjectKeyId, element, derBuffer); |
427 | 0 | LogOneKeyId(KeyIdType::kAuthorityKeyId, element, derBuffer); |
428 | 0 | } |
429 | | |
430 | | #if CHIP_PROGRESS_LOGGING |
431 | | const char * CertificationTypeAsString(CertificationType certificationType) |
432 | 0 | { |
433 | 0 | switch (certificationType) |
434 | 0 | { |
435 | 0 | case CertificationType::kDevelopmentAndTest: |
436 | 0 | return "Development and testing"; |
437 | 0 | case CertificationType::kProvisional: |
438 | 0 | return "Provisional certification"; |
439 | 0 | case CertificationType::kOfficial: |
440 | 0 | return "Certified device"; |
441 | 0 | default: |
442 | 0 | break; |
443 | 0 | } |
444 | 0 | return "<UNKNOWN>"; |
445 | 0 | } |
446 | | #endif |
447 | | |
448 | | } // namespace |
449 | | |
450 | | CHIP_ERROR DefaultDACVerifier::GetPaaCertificateAllocationSize(ByteSpan paiDer, size_t & allocationSize) |
451 | 0 | { |
452 | | // The PAI request profile describes its subject key, whereas its signature identifies |
453 | | // the PAA algorithm. A P-256 PAI can therefore require an ML-DSA PAA buffer. |
454 | 0 | using namespace ASN1; |
455 | 0 | ASN1Reader reader; |
456 | 0 | reader.Init(paiDer); |
457 | 0 | ReturnErrorOnFailure(reader.Next()); |
458 | 0 | VerifyOrReturnError(reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Sequence, |
459 | 0 | CHIP_ERROR_INVALID_ARGUMENT); |
460 | 0 | ReturnErrorOnFailure(reader.EnterConstructedType()); |
461 | 0 | ReturnErrorOnFailure(reader.Next()); // TBSCertificate |
462 | 0 | VerifyOrReturnError(reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Sequence, |
463 | 0 | CHIP_ERROR_INVALID_ARGUMENT); |
464 | 0 | ReturnErrorOnFailure(reader.Next()); // signatureAlgorithm |
465 | 0 | VerifyOrReturnError(reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_Sequence, |
466 | 0 | CHIP_ERROR_INVALID_ARGUMENT); |
467 | 0 | ReturnErrorOnFailure(reader.EnterConstructedType()); |
468 | 0 | ReturnErrorOnFailure(reader.Next()); |
469 | 0 | VerifyOrReturnError(reader.GetClass() == kASN1TagClass_Universal && reader.GetTag() == kASN1UniversalTag_ObjectId, |
470 | 0 | CHIP_ERROR_INVALID_ARGUMENT); |
471 | | |
472 | | // DER OID values for ecdsa-with-SHA256, id-ml-dsa-44, and id-ml-dsa-65. |
473 | 0 | constexpr uint8_t kEcdsaSha256[] = { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 }; |
474 | 0 | constexpr uint8_t kMlDsa44[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11 }; |
475 | 0 | constexpr uint8_t kMlDsa65[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12 }; |
476 | 0 | const ByteSpan signatureOid(reader.GetValue(), reader.GetValueLen()); |
477 | 0 | if (signatureOid.data_equal(ByteSpan(kEcdsaSha256))) |
478 | 0 | { |
479 | 0 | allocationSize = kMaxDERCertLength; |
480 | 0 | return CHIP_NO_ERROR; |
481 | 0 | } |
482 | 0 | if (signatureOid.data_equal(ByteSpan(kMlDsa44))) |
483 | 0 | { |
484 | 0 | allocationSize = kMaxDERCertLengthMlDsa44; |
485 | 0 | return Crypto::IsMlDsa44Supported() ? CHIP_NO_ERROR : CHIP_ERROR_NOT_IMPLEMENTED; |
486 | 0 | } |
487 | 0 | if (signatureOid.data_equal(ByteSpan(kMlDsa65))) |
488 | 0 | { |
489 | 0 | allocationSize = kMaxDERCertLengthMlDsa65; |
490 | 0 | return Crypto::IsMlDsa65Supported() ? CHIP_NO_ERROR : CHIP_ERROR_NOT_IMPLEMENTED; |
491 | 0 | } |
492 | 0 | return CHIP_ERROR_UNSUPPORTED_CERT_FORMAT; |
493 | 0 | } |
494 | | |
495 | | void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info, |
496 | | Callback::Callback<OnAttestationInformationVerification> * onCompletion) |
497 | 0 | { |
498 | | // The exit handler below dereferences onCompletion unconditionally; reject null here. |
499 | 0 | VerifyOrReturn(onCompletion != nullptr); |
500 | | |
501 | 0 | AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess; |
502 | |
|
503 | 0 | Platform::ScopedMemoryBuffer<uint8_t> paaCert; |
504 | 0 | MutableByteSpan paaDerBuffer; |
505 | 0 | AttestationCertVidPid dacVidPid; |
506 | 0 | AttestationCertVidPid paiVidPid; |
507 | 0 | AttestationCertVidPid paaVidPid; |
508 | 0 | size_t paaCertAllocatedLen = 0; |
509 | |
|
510 | 0 | VerifyOrExit(!info.attestationElementsBuffer.empty() && !info.attestationChallengeBuffer.empty() && |
511 | 0 | !info.attestationSignatureBuffer.empty() && !info.dacDerBuffer.empty() && !info.attestationNonceBuffer.empty(), |
512 | 0 | attestationError = AttestationVerificationResult::kInvalidArgument); |
513 | | |
514 | 0 | VerifyOrExit(info.attestationElementsBuffer.size() <= kMaxResponseLength, |
515 | 0 | attestationError = AttestationVerificationResult::kInvalidArgument); |
516 | | |
517 | 0 | if (!SupportsAttestationVerificationProfile(info.attestationProfile)) |
518 | 0 | { |
519 | 0 | ChipLogError(NotSpecified, "PQC device attestation verification is not implemented for requested profile %u", |
520 | 0 | to_underlying(info.attestationProfile)); |
521 | 0 | attestationError = AttestationVerificationResult::kNotImplemented; |
522 | 0 | ExitNow(); |
523 | 0 | } |
524 | | |
525 | | // Ensure PAI is present |
526 | 0 | VerifyOrExit(!info.paiDerBuffer.empty(), attestationError = AttestationVerificationResult::kPaiMissing); |
527 | | |
528 | | // This is an allocation/capability hint only; certificate validation below still |
529 | | // checks the PAI signature against the trusted PAA. |
530 | 0 | { |
531 | 0 | const CHIP_ERROR err = GetPaaCertificateAllocationSize(info.paiDerBuffer, paaCertAllocatedLen); |
532 | 0 | VerifyOrExit(err == CHIP_NO_ERROR, |
533 | 0 | attestationError = err == CHIP_ERROR_NOT_IMPLEMENTED ? AttestationVerificationResult::kNotImplemented |
534 | 0 | : AttestationVerificationResult::kPaiFormatInvalid); |
535 | 0 | } |
536 | | |
537 | | // Validate Proper Certificate Format |
538 | 0 | { |
539 | 0 | VerifyOrExit(VerifyAttestationCertificateFormat(info.paiDerBuffer, AttestationCertType::kPAI) == CHIP_NO_ERROR, |
540 | 0 | attestationError = AttestationVerificationResult::kPaiFormatInvalid); |
541 | 0 | VerifyOrExit(VerifyAttestationCertificateFormat(info.dacDerBuffer, AttestationCertType::kDAC) == CHIP_NO_ERROR, |
542 | 0 | attestationError = AttestationVerificationResult::kDacFormatInvalid); |
543 | 0 | } |
544 | | |
545 | | // match DAC and PAI VIDs |
546 | 0 | { |
547 | 0 | VerifyOrExit(ExtractVIDPIDFromX509Cert(info.dacDerBuffer, dacVidPid) == CHIP_NO_ERROR, |
548 | 0 | attestationError = AttestationVerificationResult::kDacFormatInvalid); |
549 | 0 | VerifyOrExit(ExtractVIDPIDFromX509Cert(info.paiDerBuffer, paiVidPid) == CHIP_NO_ERROR, |
550 | 0 | attestationError = AttestationVerificationResult::kPaiFormatInvalid); |
551 | 0 | VerifyOrExit(paiVidPid.mVendorId.HasValue() && paiVidPid.mVendorId == dacVidPid.mVendorId, |
552 | 0 | attestationError = AttestationVerificationResult::kDacVendorIdMismatch); |
553 | 0 | VerifyOrExit(dacVidPid.mProductId.HasValue(), attestationError = AttestationVerificationResult::kDacProductIdMismatch); |
554 | 0 | if (paiVidPid.mProductId.HasValue()) |
555 | 0 | { |
556 | 0 | VerifyOrExit(paiVidPid.mProductId == dacVidPid.mProductId, |
557 | 0 | attestationError = AttestationVerificationResult::kDacProductIdMismatch); |
558 | 0 | } |
559 | 0 | } |
560 | | |
561 | | // Log info about the DAC chain so far (DAC, PAI). |
562 | 0 | if (AreVerboseLogsEnabled()) |
563 | 0 | { |
564 | 0 | ChipLogProgress(NotSpecified, "Device candidate DAC chain details:"); |
565 | 0 | ChipLogProgress(NotSpecified, "--> DAC's VID: 0x%04X, PID: 0x%04X", dacVidPid.mVendorId.Value(), |
566 | 0 | dacVidPid.mProductId.Value()); |
567 | |
|
568 | 0 | LogCertDebugData(AttestationChainElement::kDAC, info.dacDerBuffer); |
569 | 0 | LogCertDebugData(AttestationChainElement::kPAI, info.paiDerBuffer); |
570 | 0 | } |
571 | | |
572 | | // Validate overall attestation signature on attestation information. |
573 | 0 | { |
574 | 0 | P256PublicKey remoteManufacturerPubkey; |
575 | 0 | P256ECDSASignature deviceSignature; |
576 | |
|
577 | 0 | VerifyOrExit(ExtractPubkeyFromX509Cert(info.dacDerBuffer, remoteManufacturerPubkey) == CHIP_NO_ERROR, |
578 | 0 | attestationError = AttestationVerificationResult::kDacFormatInvalid); |
579 | | |
580 | | // SetLength will fail if signature doesn't fit |
581 | 0 | VerifyOrExit(deviceSignature.SetLength(info.attestationSignatureBuffer.size()) == CHIP_NO_ERROR, |
582 | 0 | attestationError = AttestationVerificationResult::kAttestationSignatureInvalidFormat); |
583 | 0 | memcpy(deviceSignature.Bytes(), info.attestationSignatureBuffer.data(), info.attestationSignatureBuffer.size()); |
584 | 0 | VerifyOrExit(ValidateAttestationSignature(remoteManufacturerPubkey, info.attestationElementsBuffer, |
585 | 0 | info.attestationChallengeBuffer, deviceSignature) == CHIP_NO_ERROR, |
586 | 0 | attestationError = AttestationVerificationResult::kAttestationSignatureInvalid); |
587 | 0 | } |
588 | | |
589 | | // Find PAA and validate it. |
590 | 0 | { |
591 | 0 | uint8_t paiAkidBuf[Crypto::kAuthorityKeyIdentifierLength]; |
592 | 0 | MutableByteSpan paiAkid(paiAkidBuf); |
593 | 0 | CHIP_ERROR err = CHIP_NO_ERROR; |
594 | |
|
595 | 0 | VerifyOrExit(ExtractAKIDFromX509Cert(info.paiDerBuffer, paiAkid) == CHIP_NO_ERROR, |
596 | 0 | attestationError = AttestationVerificationResult::kPaiFormatInvalid); |
597 | | |
598 | 0 | VerifyOrExit(paaCert.Alloc(paaCertAllocatedLen), attestationError = AttestationVerificationResult::kNoMemory); |
599 | | |
600 | 0 | paaDerBuffer = MutableByteSpan(paaCert.Get(), paaCertAllocatedLen); |
601 | 0 | err = mAttestationTrustStore->GetProductAttestationAuthorityCert(paiAkid, paaDerBuffer); |
602 | 0 | if (err == CHIP_ERROR_NOT_IMPLEMENTED) |
603 | 0 | { |
604 | 0 | err = gTestAttestationTrustStore->GetProductAttestationAuthorityCert(paiAkid, paaDerBuffer); |
605 | 0 | } |
606 | |
|
607 | 0 | if (err != CHIP_NO_ERROR) |
608 | 0 | { |
609 | 0 | attestationError = AttestationVerificationResult::kPaaNotFound; |
610 | 0 | #if CHIP_ERROR_LOGGING |
611 | 0 | KeyIdStringifier paiAkidWriter; |
612 | 0 | [[maybe_unused]] const char * paiAkidHexString = paiAkidWriter.KeyIdToHex(paiAkid); |
613 | |
|
614 | 0 | ChipLogError(NotSpecified, "Unable to find PAA, err: %" CHIP_ERROR_FORMAT ", PAI's AKID: %s", err.Format(), |
615 | 0 | paiAkidHexString); |
616 | 0 | #endif // CHIP_ERROR_LOGGING |
617 | 0 | ExitNow(); |
618 | 0 | } |
619 | | |
620 | 0 | if (AreVerboseLogsEnabled()) |
621 | 0 | { |
622 | | // PAA details following the DAC/PAI above. |
623 | 0 | LogCertDebugData(AttestationChainElement::kPAA, paaDerBuffer); |
624 | 0 | } |
625 | |
|
626 | 0 | VerifyOrExit(ExtractVIDPIDFromX509Cert(paaDerBuffer, paaVidPid) == CHIP_NO_ERROR, |
627 | 0 | attestationError = AttestationVerificationResult::kPaaFormatInvalid); |
628 | | |
629 | 0 | if (paaVidPid.mVendorId.HasValue()) |
630 | 0 | { |
631 | 0 | VerifyOrExit(paaVidPid.mVendorId == paiVidPid.mVendorId, |
632 | 0 | attestationError = AttestationVerificationResult::kPaiVendorIdMismatch); |
633 | 0 | } |
634 | | |
635 | 0 | VerifyOrExit(!paaVidPid.mProductId.HasValue(), attestationError = AttestationVerificationResult::kPaaFormatInvalid); |
636 | 0 | } |
637 | | |
638 | 0 | #if !defined(CURRENT_TIME_NOT_IMPLEMENTED) |
639 | 0 | VerifyOrExit(IsCertificateValidAtCurrentTime(info.dacDerBuffer) == CHIP_NO_ERROR, |
640 | 0 | attestationError = AttestationVerificationResult::kDacExpired); |
641 | 0 | #endif |
642 | | |
643 | 0 | CertificateChainValidationResult chainValidationResult; |
644 | 0 | VerifyOrExit(ValidateCertificateChain(paaDerBuffer.data(), paaDerBuffer.size(), info.paiDerBuffer.data(), |
645 | 0 | info.paiDerBuffer.size(), info.dacDerBuffer.data(), info.dacDerBuffer.size(), |
646 | 0 | chainValidationResult) == CHIP_NO_ERROR, |
647 | 0 | attestationError = MapError(chainValidationResult)); |
648 | | |
649 | 0 | { |
650 | 0 | ByteSpan certificationDeclarationSpan; |
651 | 0 | ByteSpan attestationNonceSpan; |
652 | 0 | uint32_t timestampDeconstructed; |
653 | 0 | ByteSpan firmwareInfoSpan; |
654 | 0 | DeviceAttestationVendorReservedDeconstructor vendorReserved; |
655 | 0 | ByteSpan certificationDeclarationPayload; |
656 | |
|
657 | 0 | DeviceInfoForAttestation deviceInfo{ |
658 | 0 | .vendorId = info.vendorId, |
659 | 0 | .productId = info.productId, |
660 | 0 | .dacVendorId = dacVidPid.mVendorId.Value(), |
661 | 0 | .dacProductId = dacVidPid.mProductId.Value(), |
662 | 0 | .paiVendorId = paiVidPid.mVendorId.Value(), |
663 | 0 | .paiProductId = paiVidPid.mProductId.ValueOr(0), |
664 | 0 | .paaVendorId = paaVidPid.mVendorId.ValueOr(VendorId::NotSpecified), |
665 | 0 | }; |
666 | |
|
667 | 0 | MutableByteSpan paaSKID(deviceInfo.paaSKID); |
668 | 0 | VerifyOrExit(ExtractSKIDFromX509Cert(paaDerBuffer, paaSKID) == CHIP_NO_ERROR, |
669 | 0 | attestationError = AttestationVerificationResult::kPaaFormatInvalid); |
670 | 0 | VerifyOrExit(paaSKID.size() == sizeof(deviceInfo.paaSKID), |
671 | 0 | attestationError = AttestationVerificationResult::kPaaFormatInvalid); |
672 | | |
673 | 0 | VerifyOrExit(DeconstructAttestationElements(info.attestationElementsBuffer, certificationDeclarationSpan, |
674 | 0 | attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan, |
675 | 0 | vendorReserved) == CHIP_NO_ERROR, |
676 | 0 | attestationError = AttestationVerificationResult::kAttestationElementsMalformed); |
677 | | |
678 | | // Verify that Nonce matches with what we sent |
679 | 0 | VerifyOrExit(attestationNonceSpan.data_equal(info.attestationNonceBuffer), |
680 | 0 | attestationError = AttestationVerificationResult::kAttestationNonceMismatch); |
681 | | |
682 | 0 | attestationError = ValidateCertificationDeclarationSignature(certificationDeclarationSpan, certificationDeclarationPayload); |
683 | 0 | VerifyOrExit(attestationError == AttestationVerificationResult::kSuccess, attestationError = attestationError); |
684 | | |
685 | 0 | attestationError = ValidateCertificateDeclarationPayload(certificationDeclarationPayload, firmwareInfoSpan, deviceInfo); |
686 | 0 | VerifyOrExit(attestationError == AttestationVerificationResult::kSuccess, attestationError = attestationError); |
687 | 0 | } |
688 | | |
689 | 0 | exit: |
690 | 0 | onCompletion->mCall(onCompletion->mContext, info, attestationError); |
691 | 0 | } |
692 | | |
693 | | AttestationVerificationResult DefaultDACVerifier::ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer, |
694 | | ByteSpan & certDeclBuffer) |
695 | 0 | { |
696 | 0 | ByteSpan kid; |
697 | 0 | VerifyOrReturnError(CMS_ExtractKeyId(cmsEnvelopeBuffer, kid) == CHIP_NO_ERROR, |
698 | 0 | AttestationVerificationResult::kCertificationDeclarationNoKeyId); |
699 | | |
700 | 0 | Crypto::P256PublicKey verifyingKey; |
701 | 0 | CHIP_ERROR err = mCdKeysTrustStore.LookupVerifyingKey(kid, verifyingKey); |
702 | 0 | VerifyOrReturnError(err == CHIP_NO_ERROR, AttestationVerificationResult::kCertificationDeclarationNoCertificateFound); |
703 | | |
704 | 0 | #if CHIP_PROGRESS_LOGGING |
705 | 0 | if (AreVerboseLogsEnabled()) |
706 | 0 | { |
707 | 0 | KeyIdStringifier cdAkidWriter; |
708 | 0 | const char * cdAkidHexString = cdAkidWriter.KeyIdToHex(kid); |
709 | 0 | ChipLogProgress(NotSpecified, "CD signing key identifier: %s", cdAkidHexString); |
710 | 0 | } |
711 | 0 | #endif |
712 | |
|
713 | 0 | if (mCdKeysTrustStore.IsCdTestKey(kid)) |
714 | 0 | { |
715 | | // Disallow test key if support not enabled |
716 | 0 | if (!IsCdTestKeySupported()) |
717 | 0 | { |
718 | 0 | ChipLogError(NotSpecified, "Disallowing CD signed by test key"); |
719 | 0 | return AttestationVerificationResult::kCertificationDeclarationNoCertificateFound; |
720 | 0 | } |
721 | 0 | ChipLogProgress(NotSpecified, "Allowing CD signed by test key"); |
722 | 0 | } |
723 | | |
724 | 0 | VerifyOrReturnError(CMS_Verify(cmsEnvelopeBuffer, verifyingKey, certDeclBuffer) == CHIP_NO_ERROR, |
725 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidSignature); |
726 | | |
727 | | // certDeclBuffer is populated by CMS_Verify so we need to do this check after the signature check |
728 | 0 | CertificationElementsWithoutPIDs cdContent; |
729 | 0 | VerifyOrReturnError(DecodeCertificationElements(certDeclBuffer, cdContent) == CHIP_NO_ERROR, |
730 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidFormat); |
731 | | // Ensure we didn't use a test key for official or provisional certificates (if disallowed) |
732 | 0 | bool testKeyAllowedForCertificationType = |
733 | 0 | (cdContent.certificationType == to_underlying(CertificationType::kDevelopmentAndTest)) || |
734 | 0 | (cdContent.certificationType == to_underlying(CertificationType::kProvisional) && kEnableCdTestKeysForProvisionalCds); |
735 | 0 | ChipLogProgress(NotSpecified, "Certification type %u", cdContent.certificationType); |
736 | 0 | if (mCdKeysTrustStore.IsCdTestKey(kid) && !testKeyAllowedForCertificationType) |
737 | 0 | { |
738 | 0 | ChipLogError(NotSpecified, "Test key is disallowed for this certification type: %u", cdContent.certificationType); |
739 | 0 | return AttestationVerificationResult::kCertificationDeclarationNoCertificateFound; |
740 | 0 | } |
741 | | |
742 | 0 | return AttestationVerificationResult::kSuccess; |
743 | 0 | } |
744 | | |
745 | | AttestationVerificationResult DefaultDACVerifier::ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer, |
746 | | const ByteSpan & firmwareInfo, |
747 | | const DeviceInfoForAttestation & deviceInfo) |
748 | 0 | { |
749 | 0 | CertificationElementsWithoutPIDs cdContent; |
750 | 0 | CertificationElementsDecoder cdElementsDecoder; |
751 | 0 | VerifyOrReturnError(DecodeCertificationElements(certDeclBuffer, cdContent) == CHIP_NO_ERROR, |
752 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidFormat); |
753 | | |
754 | 0 | if (!firmwareInfo.empty()) |
755 | 0 | { |
756 | | // TODO: validate contents based on DCL |
757 | 0 | } |
758 | | |
759 | | // Verify the cd elements are as required by the spec |
760 | | // security_level, security_information are meant to be ignored. version_number is not meant to be interpreted by the |
761 | | // commissioners. |
762 | 0 | if (cdContent.formatVersion != 1 || cdContent.certificationType >= chip::to_underlying(CertificationType::kReserved)) |
763 | 0 | { |
764 | 0 | return AttestationVerificationResult::kAttestationElementsMalformed; |
765 | 0 | } |
766 | | |
767 | | // The vendor_id field in the Certification Declaration SHALL match the VendorID attribute found in the Basic Information |
768 | | // cluster |
769 | 0 | VerifyOrReturnError(cdContent.vendorId == deviceInfo.vendorId, |
770 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidVendorId); |
771 | | |
772 | | // The product_id_array field in the Certification Declaration SHALL contain the value of the ProductID attribute found in |
773 | | // the Basic Information cluster. |
774 | 0 | VerifyOrReturnError(cdElementsDecoder.IsProductIdIn(certDeclBuffer, deviceInfo.productId), |
775 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidProductId); |
776 | | |
777 | 0 | if (cdContent.dacOriginVIDandPIDPresent) |
778 | 0 | { |
779 | | // The Vendor ID (VID) subject DN in the DAC SHALL match the dac_origin_vendor_id field in the Certification |
780 | | // Declaration. |
781 | 0 | VerifyOrReturnError(deviceInfo.dacVendorId == cdContent.dacOriginVendorId, |
782 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidVendorId); |
783 | | // The Vendor ID (VID) subject DN in the PAI SHALL match the dac_origin_vendor_id field in the Certification |
784 | | // Declaration. |
785 | 0 | VerifyOrReturnError(deviceInfo.paiVendorId == cdContent.dacOriginVendorId, |
786 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidVendorId); |
787 | | // The Product ID (PID) subject DN in the DAC SHALL match the dac_origin_product_id field in the Certification |
788 | | // Declaration. |
789 | 0 | VerifyOrReturnError(deviceInfo.dacProductId == cdContent.dacOriginProductId, |
790 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidProductId); |
791 | | // The Product ID (PID) subject DN in the PAI, if such a Product ID is present, SHALL match the dac_origin_product_id |
792 | | // field in the Certification Declaration. |
793 | 0 | if (deviceInfo.paiProductId != 0) // if PAI PID is present |
794 | 0 | { |
795 | 0 | VerifyOrReturnError(deviceInfo.paiProductId == cdContent.dacOriginProductId, |
796 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidProductId); |
797 | 0 | } |
798 | 0 | } |
799 | 0 | else |
800 | 0 | { |
801 | | // The Vendor ID (VID) subject DN in the DAC SHALL match the vendor_id field in the Certification Declaration |
802 | 0 | VerifyOrReturnError(deviceInfo.dacVendorId == cdContent.vendorId, |
803 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidVendorId); |
804 | | // The Vendor ID (VID) subject DN in the PAI SHALL match the vendor_id field in the Certification Declaration. |
805 | 0 | VerifyOrReturnError(deviceInfo.paiVendorId == cdContent.vendorId, |
806 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidVendorId); |
807 | | // The Product ID (PID) subject DN in the DAC SHALL be present in the product_id_array field in the Certification |
808 | | // Declaration. |
809 | 0 | VerifyOrReturnError(cdElementsDecoder.IsProductIdIn(certDeclBuffer, deviceInfo.dacProductId), |
810 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidProductId); |
811 | | // The Product ID (PID) subject DN in the PAI, if such a Product ID is present, SHALL match one of the values present in |
812 | | // the product_id_array field in the Certification Declaration. |
813 | 0 | if (deviceInfo.paiProductId != 0) // if PAI PID is present |
814 | 0 | { |
815 | 0 | VerifyOrReturnError(cdElementsDecoder.IsProductIdIn(certDeclBuffer, deviceInfo.paiProductId), |
816 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidProductId); |
817 | 0 | } |
818 | 0 | } |
819 | | |
820 | 0 | if (cdContent.authorizedPAAListPresent) |
821 | 0 | { |
822 | | // The Subject Key Id of the PAA SHALL match one of the values present in the authorized_paa_list |
823 | | // in the Certification Declaration. |
824 | 0 | VerifyOrReturnError(cdElementsDecoder.HasAuthorizedPAA(certDeclBuffer, ByteSpan(deviceInfo.paaSKID)), |
825 | 0 | AttestationVerificationResult::kCertificationDeclarationInvalidPAA); |
826 | 0 | } |
827 | | |
828 | 0 | if (AreVerboseLogsEnabled()) |
829 | 0 | { |
830 | 0 | ChipLogProgress(NotSpecified, "Device certification declaration details:"); |
831 | 0 | ChipLogProgress(NotSpecified, "--> VID: 0x%04X", cdContent.vendorId); |
832 | | // TODO (https://github.com/project-chip/connectedhomeip/issues/39714): Figure out how to |
833 | | // log the product_id_array, which is not in cdContent. |
834 | 0 | ChipLogProgress(NotSpecified, "--> Device type ID: " ChipLogFormatMEI, ChipLogValueMEI(cdContent.deviceTypeId)); |
835 | 0 | ChipLogProgress(NotSpecified, "--> Certification type: %d (%s)", cdContent.certificationType, |
836 | 0 | CertificationTypeAsString(static_cast<CertificationType>(cdContent.certificationType))); |
837 | 0 | if (cdContent.dacOriginVIDandPIDPresent) |
838 | 0 | { |
839 | 0 | ChipLogProgress(NotSpecified, "--> DAC origin VID: 0x%04X, PID: 0x%04X", cdContent.dacOriginVendorId, |
840 | 0 | cdContent.dacOriginProductId); |
841 | 0 | } |
842 | 0 | } |
843 | |
|
844 | 0 | return AttestationVerificationResult::kSuccess; |
845 | 0 | } |
846 | | |
847 | | CHIP_ERROR DefaultDACVerifier::VerifyNodeOperationalCSRInformation(const ByteSpan & nocsrElementsBuffer, |
848 | | const ByteSpan & attestationChallengeBuffer, |
849 | | const ByteSpan & attestationSignatureBuffer, |
850 | | const P256PublicKey & dacPublicKey, const ByteSpan & csrNonce) |
851 | 0 | { |
852 | 0 | VerifyOrReturnError(!nocsrElementsBuffer.empty() && !attestationChallengeBuffer.empty() && |
853 | 0 | !attestationSignatureBuffer.empty() && !csrNonce.empty(), |
854 | 0 | CHIP_ERROR_INVALID_ARGUMENT); |
855 | | |
856 | 0 | VerifyOrReturnError(nocsrElementsBuffer.size() <= kMaxResponseLength, CHIP_ERROR_INVALID_ARGUMENT); |
857 | 0 | VerifyOrReturnError(csrNonce.size() == Controller::kCSRNonceLength, CHIP_ERROR_INVALID_ARGUMENT); |
858 | | |
859 | 0 | ByteSpan csrSpan; |
860 | 0 | ByteSpan csrNonceSpan; |
861 | 0 | ByteSpan vendorReserved1Span; |
862 | 0 | ByteSpan vendorReserved2Span; |
863 | 0 | ByteSpan vendorReserved3Span; |
864 | 0 | ReturnErrorOnFailure(DeconstructNOCSRElements(nocsrElementsBuffer, csrSpan, csrNonceSpan, vendorReserved1Span, |
865 | 0 | vendorReserved2Span, vendorReserved3Span)); |
866 | | |
867 | 0 | VerifyOrReturnError(csrNonceSpan.size() == Controller::kCSRNonceLength, CHIP_ERROR_INVALID_ARGUMENT); |
868 | | |
869 | | // Verify that Nonce matches with what we sent |
870 | 0 | VerifyOrReturnError(csrNonceSpan.data_equal(csrNonce), CHIP_ERROR_INVALID_ARGUMENT); |
871 | | |
872 | | // Validate overall attestation signature on attestation information |
873 | 0 | P256ECDSASignature signature; |
874 | | // SetLength will fail if signature doesn't fit |
875 | 0 | ReturnErrorOnFailure(signature.SetLength(attestationSignatureBuffer.size())); |
876 | 0 | memcpy(signature.Bytes(), attestationSignatureBuffer.data(), attestationSignatureBuffer.size()); |
877 | |
|
878 | 0 | ReturnErrorOnFailure(ValidateAttestationSignature(dacPublicKey, nocsrElementsBuffer, attestationChallengeBuffer, signature)); |
879 | | |
880 | 0 | return CHIP_NO_ERROR; |
881 | 0 | } |
882 | | |
883 | | void DefaultDACVerifier::CheckForRevokedDACChain(const AttestationInfo & info, |
884 | | Callback::Callback<OnAttestationInformationVerification> * onCompletion) |
885 | 0 | { |
886 | 0 | if (mRevocationDelegate != nullptr) |
887 | 0 | { |
888 | 0 | mRevocationDelegate->CheckForRevokedDACChain(info, onCompletion); |
889 | 0 | } |
890 | 0 | else |
891 | 0 | { |
892 | 0 | ChipLogProgress(NotSpecified, "WARNING: No revocation delegate available. Revocation checks will be skipped!"); |
893 | 0 | onCompletion->mCall(onCompletion->mContext, info, AttestationVerificationResult::kSuccess); |
894 | 0 | } |
895 | 0 | } |
896 | | |
897 | | bool CsaCdKeysTrustStore::IsCdTestKey(const ByteSpan & kid) const |
898 | 0 | { |
899 | 0 | return kid.data_equal(ByteSpan{ gTestCdPubkeyKid }); |
900 | 0 | } |
901 | | |
902 | | CHIP_ERROR CsaCdKeysTrustStore::AddTrustedKey(const ByteSpan & kid, const Crypto::P256PublicKey & pubKey) |
903 | 0 | { |
904 | 0 | VerifyOrReturnError(kid.size() <= SingleKeyEntry::kMaxKidSize, CHIP_ERROR_INVALID_ARGUMENT); |
905 | 0 | VerifyOrReturnError(!kid.empty(), CHIP_ERROR_INVALID_ARGUMENT); |
906 | 0 | VerifyOrReturnError(mNumTrustedKeys != kMaxNumTrustedKeys, CHIP_ERROR_NO_MEMORY); |
907 | | |
908 | 0 | auto & entry = mTrustedKeys[mNumTrustedKeys]; |
909 | |
|
910 | 0 | entry.kidSize = kid.size(); |
911 | 0 | memcpy(&entry.kidBuffer[0], kid.data(), kid.size()); |
912 | 0 | entry.publicKey = pubKey; |
913 | |
|
914 | 0 | ++mNumTrustedKeys; |
915 | 0 | return CHIP_NO_ERROR; |
916 | 0 | } |
917 | | |
918 | | CHIP_ERROR CsaCdKeysTrustStore::AddTrustedKey(const ByteSpan & derCertBytes) |
919 | 0 | { |
920 | 0 | uint8_t kidBuf[Crypto::kSubjectKeyIdentifierLength] = { 0 }; |
921 | 0 | MutableByteSpan kidSpan{ kidBuf }; |
922 | 0 | P256PublicKey pubKey; |
923 | |
|
924 | 0 | VerifyOrReturnError(CHIP_NO_ERROR == Crypto::ExtractSKIDFromX509Cert(derCertBytes, kidSpan), CHIP_ERROR_INVALID_ARGUMENT); |
925 | 0 | VerifyOrReturnError(CHIP_NO_ERROR == Crypto::ExtractPubkeyFromX509Cert(derCertBytes, pubKey), CHIP_ERROR_INVALID_ARGUMENT); |
926 | | |
927 | 0 | if (!IsCdTestKey(kidSpan)) |
928 | 0 | { |
929 | | // Verify cert against CSA CD root of trust. |
930 | 0 | CertificateChainValidationResult chainValidationResult; |
931 | 0 | VerifyOrReturnError(CHIP_NO_ERROR == |
932 | 0 | ValidateCertificateChain(gCdRootCert, sizeof(gCdRootCert), nullptr, 0, derCertBytes.data(), |
933 | 0 | derCertBytes.size(), chainValidationResult), |
934 | 0 | CHIP_ERROR_INVALID_ARGUMENT); |
935 | 0 | VerifyOrReturnError(chainValidationResult == CertificateChainValidationResult::kSuccess, CHIP_ERROR_INVALID_ARGUMENT); |
936 | 0 | } |
937 | | |
938 | 0 | return AddTrustedKey(kidSpan, pubKey); |
939 | 0 | } |
940 | | |
941 | | CHIP_ERROR CsaCdKeysTrustStore::LookupVerifyingKey(const ByteSpan & kid, Crypto::P256PublicKey & outPubKey) const |
942 | 0 | { |
943 | | // First, search for the well known keys |
944 | 0 | for (auto & cdSigningKey : gCdSigningKeys) |
945 | 0 | { |
946 | 0 | if (kid.data_equal(cdSigningKey.mKid)) |
947 | 0 | { |
948 | 0 | outPubKey = cdSigningKey.mPubkey; |
949 | 0 | return CHIP_NO_ERROR; |
950 | 0 | } |
951 | 0 | } |
952 | | |
953 | | // Seconds, search externally added keys |
954 | 0 | for (size_t keyIdx = 0; keyIdx < mNumTrustedKeys; keyIdx++) |
955 | 0 | { |
956 | 0 | auto & entry = mTrustedKeys[keyIdx]; |
957 | 0 | if (kid.data_equal(entry.GetKid())) |
958 | 0 | { |
959 | 0 | outPubKey = entry.publicKey; |
960 | 0 | return CHIP_NO_ERROR; |
961 | 0 | } |
962 | 0 | } |
963 | | |
964 | | // If we get here, the desired key was not found |
965 | 0 | return CHIP_ERROR_KEY_NOT_FOUND; |
966 | 0 | } |
967 | | |
968 | | const AttestationTrustStore * GetTestAttestationTrustStore() |
969 | 0 | { |
970 | 0 | return &gTestAttestationTrustStore.get(); |
971 | 0 | } |
972 | | |
973 | | DeviceAttestationVerifier * GetDefaultDACVerifier(const AttestationTrustStore * paaRootStore, |
974 | | DeviceAttestationRevocationDelegate * revocationDelegate) |
975 | 0 | { |
976 | 0 | static DefaultDACVerifier defaultDACVerifier{ paaRootStore, revocationDelegate }; |
977 | |
|
978 | 0 | return &defaultDACVerifier; |
979 | 0 | } |
980 | | |
981 | | } // namespace Credentials |
982 | | } // namespace chip |