Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 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 "DeviceAttestationConstructor.h"
18 : #include "DeviceAttestationVendorReserved.h"
19 :
20 : #include <lib/core/TLV.h>
21 : #include <lib/support/CodeUtils.h>
22 : #include <lib/support/logging/CHIPLogging.h>
23 :
24 : #include <cstdint>
25 :
26 : namespace chip {
27 : namespace Credentials {
28 :
29 : // context tag positions
30 : enum AttestationInfoId : uint32_t
31 : {
32 : kCertificationDeclarationTagId = 1,
33 : kAttestationNonceTagId = 2,
34 : kTimestampTagId = 3,
35 : kFirmwareInfoTagId = 4,
36 : };
37 :
38 : enum OperationalCSRInfoId : uint32_t
39 : {
40 : kCsr = 1,
41 : kCsrNonce = 2,
42 : kVendorReserved1 = 3,
43 : kVendorReserved2 = 4,
44 : kVendorReserved3 = 5,
45 : };
46 :
47 : // utility to determine number of Vendor Reserved elements in a bytespan
48 90 : CHIP_ERROR CountVendorReservedElementsInDA(const ByteSpan & attestationElements, size_t & numOfElements)
49 : {
50 90 : TLV::ContiguousBufferTLVReader tlvReader;
51 90 : TLV::TLVType containerType = TLV::kTLVType_Structure;
52 :
53 90 : tlvReader.Init(attestationElements);
54 90 : ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
55 90 : ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
56 :
57 90 : size_t count = 0;
58 : CHIP_ERROR error;
59 372 : while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
60 : {
61 282 : TLV::Tag tag = tlvReader.GetTag();
62 282 : if (TLV::IsProfileTag(tag))
63 : {
64 10 : count++;
65 : }
66 : }
67 90 : VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);
68 :
69 90 : numOfElements = count;
70 90 : return CHIP_NO_ERROR;
71 : }
72 :
73 91 : CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration,
74 : ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo,
75 : DeviceAttestationVendorReservedDeconstructor & vendorReserved)
76 : {
77 91 : bool certificationDeclarationExists = false;
78 91 : bool attestationNonceExists = false;
79 91 : bool timestampExists = false;
80 91 : bool gotFirstContextTag = false;
81 91 : uint32_t lastContextTagId = 0;
82 :
83 91 : TLV::ContiguousBufferTLVReader tlvReader;
84 91 : TLV::TLVType containerType = TLV::kTLVType_Structure;
85 :
86 91 : firmwareInfo = ByteSpan();
87 :
88 91 : tlvReader.Init(attestationElements);
89 91 : ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
90 91 : ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
91 :
92 : CHIP_ERROR error;
93 :
94 : // process context tags first (should be in sorted order)
95 363 : while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
96 : {
97 278 : TLV::Tag tag = tlvReader.GetTag();
98 278 : if (!TLV::IsContextTag(tag))
99 : {
100 5 : break;
101 : }
102 :
103 : // Ensure tag-order and correct first expected tag
104 273 : uint32_t contextTagId = TLV::TagNumFromTag(tag);
105 273 : if (!gotFirstContextTag)
106 : {
107 : // First tag must always be Certification Declaration
108 91 : VerifyOrReturnError(contextTagId == kCertificationDeclarationTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
109 90 : gotFirstContextTag = true;
110 : }
111 : else
112 : {
113 : // Subsequent tags must always be in order
114 182 : VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
115 : }
116 272 : lastContextTagId = contextTagId;
117 :
118 272 : switch (contextTagId)
119 : {
120 90 : case kCertificationDeclarationTagId:
121 90 : ReturnErrorOnFailure(tlvReader.GetByteView(certificationDeclaration));
122 90 : certificationDeclarationExists = true;
123 90 : break;
124 90 : case kAttestationNonceTagId:
125 90 : ReturnErrorOnFailure(tlvReader.GetByteView(attestationNonce));
126 90 : attestationNonceExists = true;
127 90 : break;
128 90 : case kTimestampTagId:
129 90 : ReturnErrorOnFailure(tlvReader.Get(timestamp));
130 90 : timestampExists = true;
131 90 : break;
132 1 : case kFirmwareInfoTagId:
133 1 : ReturnErrorOnFailure(tlvReader.GetByteView(firmwareInfo));
134 1 : break;
135 1 : default:
136 : // It's OK to have future context tags before vendor specific tags.
137 : // We already checked that the tags are in order.
138 1 : break;
139 : }
140 : }
141 :
142 90 : VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);
143 :
144 90 : const bool allTagsNeededPresent = certificationDeclarationExists && attestationNonceExists && timestampExists;
145 90 : VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);
146 :
147 90 : size_t count = 0;
148 90 : ReturnErrorOnFailure(CountVendorReservedElementsInDA(attestationElements, count));
149 90 : ReturnErrorOnFailure(vendorReserved.PrepareToReadVendorReservedElements(attestationElements, count));
150 90 : return CHIP_NO_ERROR;
151 : }
152 :
153 153 : CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce,
154 : uint32_t timestamp, const ByteSpan & firmwareInfo,
155 : DeviceAttestationVendorReservedConstructor & vendorReserved,
156 : MutableByteSpan & attestationElements)
157 : {
158 153 : TLV::TLVWriter tlvWriter;
159 153 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
160 :
161 153 : VerifyOrReturnError(!certificationDeclaration.empty() && !attestationNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
162 151 : VerifyOrReturnError(attestationNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);
163 :
164 150 : tlvWriter.Init(attestationElements.data(), static_cast<uint32_t>(attestationElements.size()));
165 150 : outerContainerType = TLV::kTLVType_NotSpecified;
166 150 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
167 150 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), certificationDeclaration));
168 150 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), attestationNonce));
169 150 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), timestamp));
170 150 : if (!firmwareInfo.empty())
171 : {
172 0 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), firmwareInfo));
173 : }
174 :
175 150 : const VendorReservedElement * element = vendorReserved.cbegin();
176 154 : while ((element = vendorReserved.Next()) != nullptr)
177 : {
178 4 : ReturnErrorOnFailure(
179 : tlvWriter.Put(TLV::ProfileTag(element->vendorId, element->profileNum, element->tagNum), element->vendorReservedData));
180 : }
181 :
182 150 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
183 150 : ReturnErrorOnFailure(tlvWriter.Finalize());
184 150 : attestationElements = attestationElements.SubSpan(0, tlvWriter.GetLengthWritten());
185 :
186 150 : VerifyOrReturnError(attestationElements.size() <= Credentials::kMaxRspLen, CHIP_ERROR_MESSAGE_TOO_LONG);
187 :
188 150 : return CHIP_NO_ERROR;
189 : }
190 :
191 1 : CHIP_ERROR ConstructNOCSRElements(const ByteSpan & csr, const ByteSpan & csrNonce, const ByteSpan & vendor_reserved1,
192 : const ByteSpan & vendor_reserved2, const ByteSpan & vendor_reserved3,
193 : MutableByteSpan & nocsrElements)
194 : {
195 1 : TLV::TLVWriter tlvWriter;
196 1 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
197 :
198 1 : VerifyOrReturnError(!csr.empty() && !csrNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
199 1 : VerifyOrReturnError(csrNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);
200 :
201 1 : tlvWriter.Init(nocsrElements.data(), static_cast<uint32_t>(nocsrElements.size()));
202 1 : outerContainerType = TLV::kTLVType_NotSpecified;
203 1 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
204 1 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), csr));
205 1 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), csrNonce));
206 1 : if (!vendor_reserved1.empty())
207 : {
208 1 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), vendor_reserved1));
209 : }
210 1 : if (!vendor_reserved2.empty())
211 : {
212 0 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), vendor_reserved2));
213 : }
214 1 : if (!vendor_reserved3.empty())
215 : {
216 1 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(5), vendor_reserved3));
217 : }
218 :
219 1 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
220 1 : ReturnErrorOnFailure(tlvWriter.Finalize());
221 1 : nocsrElements = nocsrElements.SubSpan(0, tlvWriter.GetLengthWritten());
222 :
223 1 : VerifyOrReturnError(nocsrElements.size() <= Credentials::kMaxRspLen, CHIP_ERROR_MESSAGE_TOO_LONG);
224 :
225 1 : return CHIP_NO_ERROR;
226 : }
227 :
228 3 : CHIP_ERROR DeconstructNOCSRElements(const ByteSpan & nocsrElements, ByteSpan & csr, ByteSpan & csrNonce,
229 : ByteSpan & vendor_reserved1, ByteSpan & vendor_reserved2, ByteSpan & vendor_reserved3)
230 : {
231 3 : bool csrExists = false;
232 3 : bool csrNonceExists = false;
233 3 : bool gotFirstContextTag = false;
234 3 : uint32_t lastContextTagId = 0;
235 :
236 3 : TLV::ContiguousBufferTLVReader tlvReader;
237 3 : TLV::TLVType containerType = TLV::kTLVType_Structure;
238 :
239 : // empty out the optional items initially
240 3 : vendor_reserved1 = vendor_reserved2 = vendor_reserved3 = ByteSpan();
241 :
242 3 : tlvReader.Init(nocsrElements);
243 3 : ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
244 3 : ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
245 :
246 : CHIP_ERROR error;
247 :
248 : // process context tags first (should be in sorted order)
249 15 : while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
250 : {
251 12 : TLV::Tag tag = tlvReader.GetTag();
252 12 : if (!TLV::IsContextTag(tag))
253 : {
254 0 : break;
255 : }
256 :
257 : // Ensure tag-order and correct first expected tag
258 12 : uint32_t contextTagId = TLV::TagNumFromTag(tag);
259 12 : if (!gotFirstContextTag)
260 : {
261 : // First tag must always be CSR
262 3 : VerifyOrReturnError(contextTagId == kCsr, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
263 3 : gotFirstContextTag = true;
264 : }
265 : else
266 : {
267 : // Subsequent tags must always be in order
268 9 : VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
269 : }
270 12 : lastContextTagId = contextTagId;
271 :
272 12 : switch (contextTagId)
273 : {
274 3 : case kCsr:
275 3 : ReturnErrorOnFailure(tlvReader.GetByteView(csr));
276 3 : csrExists = true;
277 3 : break;
278 3 : case kCsrNonce:
279 3 : ReturnErrorOnFailure(tlvReader.GetByteView(csrNonce));
280 3 : csrNonceExists = true;
281 3 : break;
282 3 : case kVendorReserved1:
283 3 : ReturnErrorOnFailure(tlvReader.Get(vendor_reserved1));
284 3 : break;
285 0 : case kVendorReserved2:
286 0 : ReturnErrorOnFailure(tlvReader.Get(vendor_reserved2));
287 0 : break;
288 3 : case kVendorReserved3:
289 3 : ReturnErrorOnFailure(tlvReader.Get(vendor_reserved3));
290 3 : break;
291 0 : default:
292 : // unrecognized TLV element
293 0 : return CHIP_ERROR_INVALID_TLV_ELEMENT;
294 : }
295 : }
296 :
297 3 : VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);
298 :
299 3 : const bool allTagsNeededPresent = csrExists && csrNonceExists;
300 3 : VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);
301 :
302 3 : return CHIP_NO_ERROR;
303 : }
304 :
305 : } // namespace Credentials
306 :
307 : } // namespace chip
|