blob: 9795270474fcc704256750df5b26ce7340eff9f0 [file] [log] [blame]
Evgeny Margolis9d175c92021-10-06 10:22:54 -07001/*
2 *
Evgeny Margolisd6a72262022-05-06 12:44:36 -07003 * Copyright (c) 2021-2022 Project CHIP Authors
Evgeny Margolis9d175c92021-10-06 10:22:54 -07004 * All rights reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/**
20 * @file
21 * This file implements data types, objects and APIs for
22 * working with Certification Declaration elements.
23 */
24
Kevin Schoedel51e5bfb2021-12-07 09:45:23 -050025#include <algorithm>
26#include <cinttypes>
27#include <cstddef>
Evgeny Margolis9d175c92021-10-06 10:22:54 -070028
29#include <credentials/CertificationDeclaration.h>
30#include <crypto/CHIPCryptoPAL.h>
31#include <lib/core/CHIPCore.h>
32#include <lib/core/CHIPSafeCasts.h>
Martin Turon82bfcd52023-01-09 13:30:38 -080033#include <lib/core/TLV.h>
Evgeny Margolis9d175c92021-10-06 10:22:54 -070034#include <lib/support/SafeInt.h>
35
36namespace chip {
37namespace Credentials {
38
39using namespace chip::ASN1;
40using namespace chip::TLV;
41using namespace chip::Crypto;
42
43static constexpr uint8_t sOID_ContentType_PKCS7Data[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
44static constexpr uint8_t sOID_ContentType_PKCS7SignedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
45static constexpr uint8_t sOID_DigestAlgo_SHA256[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
46static constexpr uint8_t sOID_SigAlgo_ECDSAWithSHA256[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 };
47
48/** Certification Declaration Element TLV Tags
49 */
50enum
51{
Evgeny Margolisa71b7842021-10-26 18:52:45 -070052 kTag_FormatVersion = 0, /**< [ unsigned int ] Format version. */
53 kTag_VendorId = 1, /**< [ unsigned int ] Vedor identifier. */
54 kTag_ProductIdArray = 2, /**< [ array ] Product identifiers (each is unsigned int). */
55 kTag_DeviceTypeId = 3, /**< [ unsigned int ] Device Type identifier. */
56 kTag_CertificateId = 4, /**< [ UTF-8 string, length 19 ] Certificate identifier. */
57 kTag_SecurityLevel = 5, /**< [ unsigned int ] Security level. */
58 kTag_SecurityInformation = 6, /**< [ unsigned int ] Security information. */
59 kTag_VersionNumber = 7, /**< [ unsigned int ] Version number. */
60 kTag_CertificationType = 8, /**< [ unsigned int ] Certification Type. */
61 kTag_DACOriginVendorId = 9, /**< [ unsigned int, optional ] DAC origin vendor identifier. */
62 kTag_DACOriginProductId = 10, /**< [ unsigned int, optional ] DAC origin product identifier. */
Evgeny Margolisd6a72262022-05-06 12:44:36 -070063 kTag_AuthorizedPAAList = 11, /**< [ array, optional ] Authorized PAA List. */
Evgeny Margolis9d175c92021-10-06 10:22:54 -070064};
65
66CHIP_ERROR EncodeCertificationElements(const CertificationElements & certElements, MutableByteSpan & encodedCertElements)
67{
68 TLVWriter writer;
69 TLVType outerContainer1, outerContainer2;
70
71 writer.Init(encodedCertElements);
72
Boris Zbarsky5c096ec2021-12-23 13:28:39 -050073 ReturnErrorOnFailure(writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainer1));
Evgeny Margolis9d175c92021-10-06 10:22:54 -070074
Evgeny Margolisa71b7842021-10-26 18:52:45 -070075 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_FormatVersion), certElements.FormatVersion));
Evgeny Margolis9d175c92021-10-06 10:22:54 -070076 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VendorId), certElements.VendorId));
77
78 VerifyOrReturnError(certElements.ProductIdsCount > 0, CHIP_ERROR_INVALID_ARGUMENT);
Evgeny Margolisd6a72262022-05-06 12:44:36 -070079 VerifyOrReturnError(certElements.ProductIdsCount <= kMaxProductIdsCount, CHIP_ERROR_INVALID_ARGUMENT);
Evgeny Margolis9d175c92021-10-06 10:22:54 -070080
Evgeny Margolisa71b7842021-10-26 18:52:45 -070081 ReturnErrorOnFailure(writer.StartContainer(ContextTag(kTag_ProductIdArray), kTLVType_Array, outerContainer2));
Evgeny Margolis9d175c92021-10-06 10:22:54 -070082 for (uint8_t i = 0; i < certElements.ProductIdsCount; i++)
83 {
Boris Zbarsky5c096ec2021-12-23 13:28:39 -050084 ReturnErrorOnFailure(writer.Put(AnonymousTag(), certElements.ProductIds[i]));
Evgeny Margolis9d175c92021-10-06 10:22:54 -070085 }
86 ReturnErrorOnFailure(writer.EndContainer(outerContainer2));
87
Evgeny Margolisa71b7842021-10-26 18:52:45 -070088 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DeviceTypeId), certElements.DeviceTypeId));
89 ReturnErrorOnFailure(writer.PutString(ContextTag(kTag_CertificateId), certElements.CertificateId));
Evgeny Margolis9d175c92021-10-06 10:22:54 -070090 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityLevel), certElements.SecurityLevel));
91 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_SecurityInformation), certElements.SecurityInformation));
92 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_VersionNumber), certElements.VersionNumber));
93 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_CertificationType), certElements.CertificationType));
Evgeny Margolisa71b7842021-10-26 18:52:45 -070094 if (certElements.DACOriginVIDandPIDPresent)
95 {
96 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginVendorId), certElements.DACOriginVendorId));
97 ReturnErrorOnFailure(writer.Put(ContextTag(kTag_DACOriginProductId), certElements.DACOriginProductId));
98 }
Evgeny Margolisd6a72262022-05-06 12:44:36 -070099 if (certElements.AuthorizedPAAListCount > 0)
100 {
101 VerifyOrReturnError(certElements.AuthorizedPAAListCount <= kMaxAuthorizedPAAListCount, CHIP_ERROR_INVALID_ARGUMENT);
102
103 ReturnErrorOnFailure(writer.StartContainer(ContextTag(kTag_AuthorizedPAAList), kTLVType_Array, outerContainer2));
104 for (uint8_t i = 0; i < certElements.AuthorizedPAAListCount; i++)
105 {
106 ReturnErrorOnFailure(writer.Put(AnonymousTag(), ByteSpan(certElements.AuthorizedPAAList[i])));
107 }
108 ReturnErrorOnFailure(writer.EndContainer(outerContainer2));
109 }
110
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700111 ReturnErrorOnFailure(writer.EndContainer(outerContainer1));
112
113 ReturnErrorOnFailure(writer.Finalize());
114
115 encodedCertElements.reduce_size(writer.GetLengthWritten());
116
117 return CHIP_NO_ERROR;
118}
119
120CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, CertificationElements & certElements)
121{
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700122 CHIP_ERROR err;
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700123 TLVReader reader;
124 TLVType outerContainer1, outerContainer2;
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700125
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500126 VerifyOrReturnError(encodedCertElements.size() <= kMaxCMSSignedCDMessage, CHIP_ERROR_INVALID_ARGUMENT);
127
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700128 reader.Init(encodedCertElements);
129
Boris Zbarsky5c096ec2021-12-23 13:28:39 -0500130 ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag()));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700131
132 ReturnErrorOnFailure(reader.EnterContainer(outerContainer1));
133
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700134 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_FormatVersion)));
135 ReturnErrorOnFailure(reader.Get(certElements.FormatVersion));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700136
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700137 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VendorId)));
138 ReturnErrorOnFailure(reader.Get(certElements.VendorId));
139
140 ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(kTag_ProductIdArray)));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700141 ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
142
143 certElements.ProductIdsCount = 0;
Boris Zbarsky5c096ec2021-12-23 13:28:39 -0500144 while ((err = reader.Next(AnonymousTag())) == CHIP_NO_ERROR)
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700145 {
Robert Szewczyk596741a2023-10-10 05:53:43 -0700146 VerifyOrReturnError(certElements.ProductIdsCount < kMaxProductIdsCount, CHIP_ERROR_INVALID_ARGUMENT);
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700147 ReturnErrorOnFailure(reader.Get(certElements.ProductIds[certElements.ProductIdsCount++]));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700148 }
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700149 VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700150 ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
151
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700152 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DeviceTypeId)));
153 ReturnErrorOnFailure(reader.Get(certElements.DeviceTypeId));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700154
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700155 ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, ContextTag(kTag_CertificateId)));
156 ReturnErrorOnFailure(reader.GetString(certElements.CertificateId, sizeof(certElements.CertificateId)));
157 VerifyOrReturnError(strlen(certElements.CertificateId) == kCertificateIdLength, CHIP_ERROR_INVALID_TLV_ELEMENT);
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700158
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700159 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityLevel)));
160 ReturnErrorOnFailure(reader.Get(certElements.SecurityLevel));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700161
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700162 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityInformation)));
163 ReturnErrorOnFailure(reader.Get(certElements.SecurityInformation));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700164
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700165 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VersionNumber)));
166 ReturnErrorOnFailure(reader.Get(certElements.VersionNumber));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700167
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700168 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_CertificationType)));
169 ReturnErrorOnFailure(reader.Get(certElements.CertificationType));
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700170
Evgeny Margolisa71b7842021-10-26 18:52:45 -0700171 certElements.DACOriginVIDandPIDPresent = false;
172
173 // If kTag_DACOriginVendorId present then kTag_DACOriginProductId must be present.
174 if ((err = reader.Next(ContextTag(kTag_DACOriginVendorId))) == CHIP_NO_ERROR)
175 {
176 ReturnErrorOnFailure(reader.Get(certElements.DACOriginVendorId));
177
178 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DACOriginProductId)));
179 ReturnErrorOnFailure(reader.Get(certElements.DACOriginProductId));
180
181 certElements.DACOriginVIDandPIDPresent = true;
182
183 err = reader.Next();
184 }
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500185 VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
Evgeny Margolisaa2f2252022-10-03 10:13:00 -0700186 VerifyOrReturnError(reader.GetTag() != TLV::ContextTag(kTag_DACOriginProductId), CHIP_ERROR_INVALID_TLV_ELEMENT);
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700187
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700188 if (err != CHIP_END_OF_TLV && reader.GetTag() == ContextTag(kTag_AuthorizedPAAList))
189 {
190 VerifyOrReturnError(reader.GetType() == kTLVType_Array, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
191
192 ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
193
194 certElements.AuthorizedPAAListCount = 0;
195 while ((err = reader.Next(kTLVType_ByteString, AnonymousTag())) == CHIP_NO_ERROR)
196 {
197 VerifyOrReturnError(reader.GetLength() == kKeyIdentifierLength, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
Robert Szewczyk596741a2023-10-10 05:53:43 -0700198 VerifyOrReturnError(certElements.AuthorizedPAAListCount < kMaxAuthorizedPAAListCount, CHIP_ERROR_INVALID_ARGUMENT);
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700199
200 ReturnErrorOnFailure(
201 reader.GetBytes(certElements.AuthorizedPAAList[certElements.AuthorizedPAAListCount++], kKeyIdentifierLength));
202 }
203 VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
204 ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
205
206 err = reader.Next();
207 }
208 VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
209
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700210 ReturnErrorOnFailure(reader.ExitContainer(outerContainer1));
211
212 ReturnErrorOnFailure(reader.VerifyEndOfContainer());
213
214 return CHIP_NO_ERROR;
215}
216
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500217CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, CertificationElementsWithoutPIDs & certDeclContent)
218{
219 CHIP_ERROR err;
220 TLVReader reader;
221 TLVType outerContainer;
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700222 TLVType outerContainer2;
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500223
224 VerifyOrReturnError(encodedCertElements.size() <= kMaxCMSSignedCDMessage, CHIP_ERROR_INVALID_ARGUMENT);
225
226 reader.Init(encodedCertElements);
227
Boris Zbarsky5c096ec2021-12-23 13:28:39 -0500228 ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag()));
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500229
230 ReturnErrorOnFailure(reader.EnterContainer(outerContainer));
231
232 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_FormatVersion)));
233 ReturnErrorOnFailure(reader.Get(certDeclContent.formatVersion));
234
235 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VendorId)));
236 ReturnErrorOnFailure(reader.Get(certDeclContent.vendorId));
237
238 ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(kTag_ProductIdArray)));
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700239 ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500240
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700241 while ((err = reader.Next(kTLVType_UnsignedInteger, AnonymousTag())) == CHIP_NO_ERROR)
242 {
243 // Verifies that the TLV structure of PID Array is correct
244 // but skip the values
245 }
246 VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
247 ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500248
249 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DeviceTypeId)));
250 ReturnErrorOnFailure(reader.Get(certDeclContent.deviceTypeId));
251
252 ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, ContextTag(kTag_CertificateId)));
253 ReturnErrorOnFailure(reader.GetString(certDeclContent.certificateId, sizeof(certDeclContent.certificateId)));
254 VerifyOrReturnError(strlen(certDeclContent.certificateId) == kCertificateIdLength, CHIP_ERROR_INVALID_TLV_ELEMENT);
255
256 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityLevel)));
257 ReturnErrorOnFailure(reader.Get(certDeclContent.securityLevel));
258
259 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityInformation)));
260 ReturnErrorOnFailure(reader.Get(certDeclContent.securityInformation));
261
262 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VersionNumber)));
263 ReturnErrorOnFailure(reader.Get(certDeclContent.versionNumber));
264
265 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_CertificationType)));
266 ReturnErrorOnFailure(reader.Get(certDeclContent.certificationType));
267
268 certDeclContent.dacOriginVIDandPIDPresent = false;
269
270 // If kTag_DACOriginVendorId present then kTag_DACOriginProductId must be present.
271 if ((err = reader.Next(ContextTag(kTag_DACOriginVendorId))) == CHIP_NO_ERROR)
272 {
273 ReturnErrorOnFailure(reader.Get(certDeclContent.dacOriginVendorId));
274
275 ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DACOriginProductId)));
276 ReturnErrorOnFailure(reader.Get(certDeclContent.dacOriginProductId));
277
278 certDeclContent.dacOriginVIDandPIDPresent = true;
279
280 err = reader.Next();
281 }
282 VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
Evgeny Margolisaa2f2252022-10-03 10:13:00 -0700283 VerifyOrReturnError(reader.GetTag() != TLV::ContextTag(kTag_DACOriginProductId), CHIP_ERROR_INVALID_TLV_ELEMENT);
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500284
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700285 if (err != CHIP_END_OF_TLV && reader.GetTag() == ContextTag(kTag_AuthorizedPAAList))
286 {
287 VerifyOrReturnError(reader.GetType() == kTLVType_Array, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
288
289 ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));
290
291 while ((err = reader.Next(kTLVType_ByteString, AnonymousTag())) == CHIP_NO_ERROR)
292 {
293 VerifyOrReturnError(reader.GetLength() == kKeyIdentifierLength, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
294 // Verifies that the TLV structure of the Authorized PAA List is correct
295 // but skip the values
296 }
297 VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
298
299 ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));
300
301 certDeclContent.authorizedPAAListPresent = true;
302
303 err = reader.Next();
304 }
305 VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);
306
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500307 ReturnErrorOnFailure(reader.ExitContainer(outerContainer));
308
309 ReturnErrorOnFailure(reader.VerifyEndOfContainer());
310
311 return CHIP_NO_ERROR;
312}
313
314bool CertificationElementsDecoder::IsProductIdIn(const ByteSpan & encodedCertElements, uint16_t productId)
315{
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700316 VerifyOrReturnError(FindAndEnterArray(encodedCertElements, ContextTag(kTag_ProductIdArray)) == CHIP_NO_ERROR, false);
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500317
318 uint16_t cdProductId = 0;
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700319 while (GetNextProductId(cdProductId) == CHIP_NO_ERROR)
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500320 {
321 if (productId == cdProductId)
322 {
323 return true;
324 }
325 }
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500326 return false;
327}
328
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700329CHIP_ERROR CertificationElementsDecoder::FindAndEnterArray(const ByteSpan & encodedCertElements, Tag arrayTag)
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500330{
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700331 TLVType outerContainerType1;
332 TLVType outerContainerType2;
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500333
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700334 mReader.Init(encodedCertElements);
Boris Zbarsky5c096ec2021-12-23 13:28:39 -0500335 ReturnErrorOnFailure(mReader.Next(kTLVType_Structure, AnonymousTag()));
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700336 ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType1));
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500337
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700338 // position to arrayTag Array
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500339 do
340 {
Karsten Sperlingd9cf44b2023-11-03 18:49:50 +1300341 ReturnErrorOnFailure(mReader.Next());
342 } while (mReader.Expect(kTLVType_Array, arrayTag) != CHIP_NO_ERROR);
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500343
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700344 ReturnErrorOnFailure(mReader.EnterContainer(outerContainerType2));
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500345
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500346 return CHIP_NO_ERROR;
347}
348
349CHIP_ERROR CertificationElementsDecoder::GetNextProductId(uint16_t & productId)
350{
Boris Zbarsky5c096ec2021-12-23 13:28:39 -0500351 ReturnErrorOnFailure(mReader.Next(AnonymousTag()));
Vijay Selvaraj098e7362021-11-23 12:02:00 -0500352 ReturnErrorOnFailure(mReader.Get(productId));
353 return CHIP_NO_ERROR;
354}
355
Evgeny Margolisd6a72262022-05-06 12:44:36 -0700356bool CertificationElementsDecoder::HasAuthorizedPAA(const ByteSpan & encodedCertElements, const ByteSpan & authorizedPAA)
357{
358 VerifyOrReturnError(FindAndEnterArray(encodedCertElements, ContextTag(kTag_AuthorizedPAAList)) == CHIP_NO_ERROR, false);
359
360 ByteSpan cdAuthorizedPAA;
361 while (GetNextAuthorizedPAA(cdAuthorizedPAA) == CHIP_NO_ERROR)
362 {
363 if (authorizedPAA.data_equal(cdAuthorizedPAA))
364 {
365 return true;
366 }
367 }
368 return false;
369}
370
371CHIP_ERROR CertificationElementsDecoder::GetNextAuthorizedPAA(ByteSpan & authorizedPAA)
372{
373 ReturnErrorOnFailure(mReader.Next(AnonymousTag()));
374 ReturnErrorOnFailure(mReader.Get(authorizedPAA));
375 return CHIP_NO_ERROR;
376}
377
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700378namespace {
379
380CHIP_ERROR EncodeEncapsulatedContent(const ByteSpan & cdContent, ASN1Writer & writer)
381{
382 /**
383 * EncapsulatedContentInfo ::= SEQUENCE {
384 * eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1),
385 * eContent [0] EXPLICIT OCTET STRING cd_content }
386 */
387 CHIP_ERROR err = CHIP_NO_ERROR;
388
389 ASN1_START_SEQUENCE
390 {
391 // eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1)
392 ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_PKCS7Data, sizeof(sOID_ContentType_PKCS7Data)));
393
394 // eContent [0] EXPLICIT OCTET STRING cd_content
395 ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
396 {
397 // OCTET STRING cd_content
398 ReturnErrorOnFailure(writer.PutOctetString(cdContent.data(), static_cast<uint16_t>(cdContent.size())));
399 }
400 ASN1_END_CONSTRUCTED;
401 }
402 ASN1_END_SEQUENCE;
403
404exit:
405 return err;
406}
407
408CHIP_ERROR DecodeEncapsulatedContent(ASN1Reader & reader, ByteSpan & cdContent)
409{
410 /**
411 * EncapsulatedContentInfo ::= SEQUENCE {
412 * eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1),
413 * eContent [0] EXPLICIT OCTET STRING cd_content }
414 */
415 CHIP_ERROR err = CHIP_NO_ERROR;
416
417 ASN1_PARSE_ENTER_SEQUENCE
418 {
419 // eContentType OBJECT IDENTIFIER pkcs7-data (1.2.840.113549.1.7.1)
420 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
421 VerifyOrReturnError(ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_ContentType_PKCS7Data)),
422 ASN1_ERROR_UNSUPPORTED_ENCODING);
423
424 // eContent [0] EXPLICIT OCTET STRING cd_content
425 ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
426 {
427 // OCTET STRING cd_content
428 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
429 cdContent = ByteSpan(reader.GetValue(), reader.GetValueLen());
430 }
431 ASN1_EXIT_CONSTRUCTED;
432 }
433 ASN1_EXIT_SEQUENCE;
434
435exit:
436 return err;
437}
438
439CHIP_ERROR EncodeSignerInfo(const ByteSpan & signerKeyId, const P256ECDSASignature & signature, ASN1Writer & writer)
440{
441 /**
442 * SignerInfo ::= SEQUENCE {
443 * version INTEGER ( v3(3) ),
444 * subjectKeyIdentifier OCTET STRING,
445 * digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
446 * signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2),
447 * signature OCTET STRING }
448 */
449 CHIP_ERROR err = CHIP_NO_ERROR;
450
451 ASN1_START_SET
452 {
453 ASN1_START_SEQUENCE
454 {
455 // version INTEGER ( v3(3) )
456 ASN1_ENCODE_INTEGER(3);
457
458 // subjectKeyIdentifier OCTET STRING
459 ReturnErrorOnFailure(writer.PutOctetString(kASN1TagClass_ContextSpecific, 0, signerKeyId.data(),
460 static_cast<uint16_t>(signerKeyId.size())));
461
462 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
463 ASN1_START_SEQUENCE
464 {
465 ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
466 }
467 ASN1_END_SEQUENCE;
468
469 // signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
Karsten Sperling38d6a482023-09-29 15:50:08 +1300470 ASN1_START_SEQUENCE
471 {
472 ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
473 }
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700474 ASN1_END_SEQUENCE;
475
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700476 // signature OCTET STRING
Karsten Sperlingaaa94052023-12-21 07:08:45 +1300477 ASN1_START_OCTET_STRING_ENCAPSULATED
478 {
479 ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan(signature.ConstBytes()), writer));
480 }
481 ASN1_END_ENCAPSULATED;
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700482 }
483 ASN1_END_SEQUENCE;
484 }
485 ASN1_END_SET;
486
487exit:
488 return err;
489}
490
491CHIP_ERROR DecodeSignerInfo(ASN1Reader & reader, ByteSpan & signerKeyId, P256ECDSASignature & signature)
492{
493 /**
494 * SignerInfo ::= SEQUENCE {
495 * version INTEGER ( v3(3) ),
496 * subjectKeyIdentifier OCTET STRING,
497 * digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
498 * signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2),
499 * signature OCTET STRING }
500 */
501 CHIP_ERROR err = CHIP_NO_ERROR;
502
503 ASN1_PARSE_ENTER_SET
504 {
505 ASN1_PARSE_ENTER_SEQUENCE
506 {
507 // version INTEGER ( v3(3) )
508 {
509 int64_t version;
510 ASN1_PARSE_INTEGER(version);
511
512 // Verify that the CMS version is v3
513 VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
514 }
515
516 // subjectKeyIdentifier OCTET STRING
517 ASN1_PARSE_ELEMENT(kASN1TagClass_ContextSpecific, 0);
518 signerKeyId = ByteSpan(reader.GetValue(), reader.GetValueLen());
519
520 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
521 ASN1_PARSE_ENTER_SEQUENCE
522 {
523 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
524 VerifyOrReturnError(ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
525 ASN1_ERROR_UNSUPPORTED_ENCODING);
526 }
527 ASN1_EXIT_SEQUENCE;
528
529 // signatureAlgorithm OBJECT IDENTIFIER ecdsa-with-SHA256 (1.2.840.10045.4.3.2)
530 ASN1_PARSE_ENTER_SEQUENCE
531 {
532 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
533 VerifyOrReturnError(
534 ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_SigAlgo_ECDSAWithSHA256)),
535 ASN1_ERROR_UNSUPPORTED_ENCODING);
536 }
537 ASN1_EXIT_SEQUENCE;
538
539 // signature OCTET STRING
540 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_OctetString);
541
Damian Królik9b636332023-01-15 05:42:02 +0100542 MutableByteSpan signatureSpan(signature.Bytes(), signature.Capacity());
Evgeny Margolis9d175c92021-10-06 10:22:54 -0700543 ReturnErrorOnFailure(
544 EcdsaAsn1SignatureToRaw(kP256_FE_Length, ByteSpan(reader.GetValue(), reader.GetValueLen()), signatureSpan));
545 ReturnErrorOnFailure(signature.SetLength(signatureSpan.size()));
546 }
547 ASN1_EXIT_SEQUENCE;
548 }
549 ASN1_EXIT_SET;
550
551exit:
552 return err;
553}
554
555} // namespace
556
557CHIP_ERROR CMS_Sign(const ByteSpan & cdContent, const ByteSpan & signerKeyId, Crypto::P256Keypair & signerKeypair,
558 MutableByteSpan & signedMessage)
559{
560 /**
561 * CertificationDeclaration ::= SEQUENCE {
562 * version INTEGER ( v3(3) ),
563 * digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1),
564 * encapContentInfo EncapsulatedContentInfo,
565 * signerInfo SignerInfo }
566 */
567 CHIP_ERROR err = CHIP_NO_ERROR;
568 ASN1Writer writer;
569 uint32_t size = static_cast<uint32_t>(std::min(static_cast<size_t>(UINT32_MAX), signedMessage.size()));
570
571 writer.Init(signedMessage.data(), size);
572
573 ASN1_START_SEQUENCE
574 {
575 // OID identifies the CMS signed-data content type
576 ReturnErrorOnFailure(writer.PutObjectId(sOID_ContentType_PKCS7SignedData, sizeof(sOID_ContentType_PKCS7SignedData)));
577
578 ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
579 {
580 ASN1_START_SEQUENCE
581 {
582 // version INTEGER ( v3(3) )
583 ASN1_ENCODE_INTEGER(3);
584
585 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
586 ASN1_START_SET
587 {
588 ASN1_START_SEQUENCE
589 {
590 ReturnErrorOnFailure(writer.PutObjectId(sOID_DigestAlgo_SHA256, sizeof(sOID_DigestAlgo_SHA256)));
591 }
592 ASN1_END_SEQUENCE;
593 }
594 ASN1_END_SET;
595
596 // encapContentInfo EncapsulatedContentInfo
597 ReturnErrorOnFailure(EncodeEncapsulatedContent(cdContent, writer));
598
599 Crypto::P256ECDSASignature signature;
600 ReturnErrorOnFailure(signerKeypair.ECDSA_sign_msg(cdContent.data(), cdContent.size(), signature));
601
602 // signerInfo SignerInfo
603 ReturnErrorOnFailure(EncodeSignerInfo(signerKeyId, signature, writer));
604 }
605 ASN1_END_SEQUENCE;
606 }
607 ASN1_END_CONSTRUCTED;
608 }
609 ASN1_END_SEQUENCE;
610
611 signedMessage.reduce_size(writer.GetLengthWritten());
612
613exit:
614 return err;
615}
616
617CHIP_ERROR CMS_Verify(const ByteSpan & signedMessage, const ByteSpan & signerX509Cert, ByteSpan & cdContent)
618{
619 P256PublicKey signerPubkey;
620
621 ReturnErrorOnFailure(ExtractPubkeyFromX509Cert(signerX509Cert, signerPubkey));
622
623 return CMS_Verify(signedMessage, signerPubkey, cdContent);
624}
625
626CHIP_ERROR CMS_Verify(const ByteSpan & signedMessage, const Crypto::P256PublicKey & signerPubkey, ByteSpan & cdContent)
627{
628 CHIP_ERROR err = CHIP_NO_ERROR;
629 ASN1Reader reader;
630 uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
631
632 reader.Init(signedMessage.data(), size);
633
634 // SignedData ::= SEQUENCE
635 ASN1_PARSE_ENTER_SEQUENCE
636 {
637 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
638
639 // id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
640 // OID identifies the CMS signed-data content type
641 VerifyOrReturnError(
642 ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_ContentType_PKCS7SignedData)),
643 ASN1_ERROR_UNSUPPORTED_ENCODING);
644
645 // version [0] EXPLICIT Version DEFAULT v3
646 ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
647 {
648 ASN1_PARSE_ENTER_SEQUENCE
649 {
650 // Version ::= INTEGER { v3(3) }
651 int64_t version;
652 ASN1_PARSE_INTEGER(version);
653
654 // Verify that the CMS version is v3
655 VerifyOrExit(version == 3, err = ASN1_ERROR_UNSUPPORTED_ENCODING);
656
657 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
658 ASN1_PARSE_ENTER_SET
659 {
660 ASN1_PARSE_ENTER_SEQUENCE
661 {
662 ASN1_PARSE_ELEMENT(kASN1TagClass_Universal, kASN1UniversalTag_ObjectId);
663 VerifyOrReturnError(
664 ByteSpan(reader.GetValue(), reader.GetValueLen()).data_equal(ByteSpan(sOID_DigestAlgo_SHA256)),
665 ASN1_ERROR_UNSUPPORTED_ENCODING);
666 }
667 ASN1_EXIT_SEQUENCE;
668 }
669 ASN1_EXIT_SET;
670
671 // encapContentInfo EncapsulatedContentInfo
672 ReturnErrorOnFailure(DecodeEncapsulatedContent(reader, cdContent));
673
674 // signerInfo SignerInfo
675 ByteSpan signerKeyId;
676 P256ECDSASignature signature;
677 ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
678
679 // Validate CD Signature
680 ReturnErrorOnFailure(signerPubkey.ECDSA_validate_msg_signature(cdContent.data(), cdContent.size(), signature));
681 }
682 ASN1_EXIT_SEQUENCE;
683 }
684 ASN1_EXIT_CONSTRUCTED;
685 }
686 ASN1_EXIT_SEQUENCE;
687
688exit:
689 return err;
690}
691
692CHIP_ERROR CMS_ExtractKeyId(const ByteSpan & signedMessage, ByteSpan & signerKeyId)
693{
694 CHIP_ERROR err = CHIP_NO_ERROR;
695 ASN1Reader reader;
696 uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
697
698 reader.Init(signedMessage.data(), size);
699
700 // SignedData ::= SEQUENCE
701 ASN1_PARSE_ENTER_SEQUENCE
702 {
703 // id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
704 // OID identifies the CMS signed-data content type
705 ASN1_PARSE_ANY;
706
707 // version [0] EXPLICIT Version DEFAULT v3
708 ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
709 {
710 ASN1_PARSE_ENTER_SEQUENCE
711 {
712 // Version ::= INTEGER { v3(3) }
713 ASN1_PARSE_ANY;
714
715 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
716 ASN1_PARSE_ANY;
717
718 // encapContentInfo EncapsulatedContentInfo
719 ASN1_PARSE_ANY;
720
721 // signerInfo SignerInfo
722 P256ECDSASignature signature;
723 ReturnErrorOnFailure(DecodeSignerInfo(reader, signerKeyId, signature));
724 }
725 ASN1_EXIT_SEQUENCE;
726 }
727 ASN1_EXIT_CONSTRUCTED;
728 }
729 ASN1_EXIT_SEQUENCE;
730
731exit:
732 return err;
733}
734
735CHIP_ERROR CMS_ExtractCDContent(const ByteSpan & signedMessage, ByteSpan & cdContent)
736{
737 CHIP_ERROR err = CHIP_NO_ERROR;
738 ASN1Reader reader;
739 uint32_t size = signedMessage.size() > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(signedMessage.size());
740
741 reader.Init(signedMessage.data(), size);
742
743 // SignedData ::= SEQUENCE
744 ASN1_PARSE_ENTER_SEQUENCE
745 {
746 // id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
747 // OID identifies the CMS signed-data content type
748 ASN1_PARSE_ANY;
749
750 // version [0] EXPLICIT Version DEFAULT v3
751 ASN1_PARSE_ENTER_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
752 {
753 ASN1_PARSE_ENTER_SEQUENCE
754 {
755 // Version ::= INTEGER { v3(3) }
756 ASN1_PARSE_ANY;
757
758 // digestAlgorithm OBJECT IDENTIFIER sha256 (2.16.840.1.101.3.4.2.1)
759 ASN1_PARSE_ANY;
760
761 // encapContentInfo EncapsulatedContentInfo
762 ReturnErrorOnFailure(DecodeEncapsulatedContent(reader, cdContent));
763
764 // signerInfo SignerInfo
765 ASN1_PARSE_ANY;
766 }
767 ASN1_EXIT_SEQUENCE;
768 }
769 ASN1_EXIT_CONSTRUCTED;
770 }
771 ASN1_EXIT_SEQUENCE;
772
773exit:
774 return err;
775}
776
777} // namespace Credentials
778} // namespace chip