Coverage Report

Created: 2026-09-24 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/connectedhomeip/src/app/tests/suites/credentials/TestHarnessDACProvider.cpp
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 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 "TestHarnessDACProvider.h"
18
19
#include <credentials/CHIPCert.h>
20
#include <credentials/CertificationDeclaration.h>
21
#include <credentials/examples/ExampleDACs.h>
22
#include <credentials/examples/ExamplePAI.h>
23
#include <crypto/CHIPCryptoPAL.h>
24
#include <json/json.h>
25
#include <lib/core/CHIPError.h>
26
#include <lib/support/BytesToHex.h>
27
#include <lib/support/Span.h>
28
#include <platform/CHIPDeviceConfig.h>
29
30
#include <algorithm>
31
#include <fstream>
32
#include <string>
33
34
//-> format_version = 1
35
//-> vendor_id = 0xFFF1/0xFFF2/0xFFF3
36
//-> product_id_array = [ 0x8000, 0x8001, 0x8002, 0x8003, 0x8004, 0x8005, 0x8006, 0x8007, 0x8008, 0x8009, 0x800A, 0x800B,
37
// 0x800C, 0x800D, 0x800E, 0x800F, 0x8010, 0x8011, 0x8012, 0x8013, 0x8014, 0x8015, 0x8016, 0x8017, 0x8018, 0x8019, 0x801A,
38
// 0x801B, 0x801C, 0x801D, 0x801E, 0x801F, 0x8020, 0x8021, 0x8022, 0x8023, 0x8024, 0x8025, 0x8026, 0x8027, 0x8028, 0x8029,
39
// 0x802A, 0x802B, 0x802C, 0x802D, 0x802E, 0x802F, 0x8030, 0x8031, 0x8032, 0x8033, 0x8034, 0x8035, 0x8036, 0x8037, 0x8038,
40
// 0x8039, 0x803A, 0x803B, 0x803C, 0x803D, 0x803E, 0x803F, 0x8040, 0x8041, 0x8042, 0x8043, 0x8044, 0x8045, 0x8046, 0x8047,
41
// 0x8048, 0x8049, 0x804A, 0x804B, 0x804C, 0x804D, 0x804E, 0x804F, 0x8050, 0x8051, 0x8052, 0x8053, 0x8054, 0x8055, 0x8056,
42
// 0x8057, 0x8058, 0x8059, 0x805A, 0x805B, 0x805C, 0x805D, 0x805E, 0x805F, 0x8060, 0x8061, 0x8062, 0x8063 ]
43
//-> device_type_id = 0x0016
44
//-> certificate_id = "CSA00000SWC00000-00"
45
//-> security_level = 0
46
//-> security_information = 0
47
//-> version_number = 1
48
//-> certification_type = 0
49
//-> dac_origin_vendor_id is not present
50
//-> dac_origin_product_id is not present
51
#if CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID == 0xFFF2
52
constexpr const uint8_t kCdForAllExamples[] = {
53
    0x30, 0x82, 0x02, 0x19, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0x0a, 0x30, 0x82,
54
    0x02, 0x06, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30,
55
    0x82, 0x01, 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x01, 0x61, 0x04, 0x82, 0x01,
56
    0x5d, 0x15, 0x24, 0x00, 0x01, 0x25, 0x01, 0xf2, 0xff, 0x36, 0x02, 0x05, 0x00, 0x80, 0x05, 0x01, 0x80, 0x05, 0x02, 0x80, 0x05,
57
    0x03, 0x80, 0x05, 0x04, 0x80, 0x05, 0x05, 0x80, 0x05, 0x06, 0x80, 0x05, 0x07, 0x80, 0x05, 0x08, 0x80, 0x05, 0x09, 0x80, 0x05,
58
    0x0a, 0x80, 0x05, 0x0b, 0x80, 0x05, 0x0c, 0x80, 0x05, 0x0d, 0x80, 0x05, 0x0e, 0x80, 0x05, 0x0f, 0x80, 0x05, 0x10, 0x80, 0x05,
59
    0x11, 0x80, 0x05, 0x12, 0x80, 0x05, 0x13, 0x80, 0x05, 0x14, 0x80, 0x05, 0x15, 0x80, 0x05, 0x16, 0x80, 0x05, 0x17, 0x80, 0x05,
60
    0x18, 0x80, 0x05, 0x19, 0x80, 0x05, 0x1a, 0x80, 0x05, 0x1b, 0x80, 0x05, 0x1c, 0x80, 0x05, 0x1d, 0x80, 0x05, 0x1e, 0x80, 0x05,
61
    0x1f, 0x80, 0x05, 0x20, 0x80, 0x05, 0x21, 0x80, 0x05, 0x22, 0x80, 0x05, 0x23, 0x80, 0x05, 0x24, 0x80, 0x05, 0x25, 0x80, 0x05,
62
    0x26, 0x80, 0x05, 0x27, 0x80, 0x05, 0x28, 0x80, 0x05, 0x29, 0x80, 0x05, 0x2a, 0x80, 0x05, 0x2b, 0x80, 0x05, 0x2c, 0x80, 0x05,
63
    0x2d, 0x80, 0x05, 0x2e, 0x80, 0x05, 0x2f, 0x80, 0x05, 0x30, 0x80, 0x05, 0x31, 0x80, 0x05, 0x32, 0x80, 0x05, 0x33, 0x80, 0x05,
64
    0x34, 0x80, 0x05, 0x35, 0x80, 0x05, 0x36, 0x80, 0x05, 0x37, 0x80, 0x05, 0x38, 0x80, 0x05, 0x39, 0x80, 0x05, 0x3a, 0x80, 0x05,
65
    0x3b, 0x80, 0x05, 0x3c, 0x80, 0x05, 0x3d, 0x80, 0x05, 0x3e, 0x80, 0x05, 0x3f, 0x80, 0x05, 0x40, 0x80, 0x05, 0x41, 0x80, 0x05,
66
    0x42, 0x80, 0x05, 0x43, 0x80, 0x05, 0x44, 0x80, 0x05, 0x45, 0x80, 0x05, 0x46, 0x80, 0x05, 0x47, 0x80, 0x05, 0x48, 0x80, 0x05,
67
    0x49, 0x80, 0x05, 0x4a, 0x80, 0x05, 0x4b, 0x80, 0x05, 0x4c, 0x80, 0x05, 0x4d, 0x80, 0x05, 0x4e, 0x80, 0x05, 0x4f, 0x80, 0x05,
68
    0x50, 0x80, 0x05, 0x51, 0x80, 0x05, 0x52, 0x80, 0x05, 0x53, 0x80, 0x05, 0x54, 0x80, 0x05, 0x55, 0x80, 0x05, 0x56, 0x80, 0x05,
69
    0x57, 0x80, 0x05, 0x58, 0x80, 0x05, 0x59, 0x80, 0x05, 0x5a, 0x80, 0x05, 0x5b, 0x80, 0x05, 0x5c, 0x80, 0x05, 0x5d, 0x80, 0x05,
70
    0x5e, 0x80, 0x05, 0x5f, 0x80, 0x05, 0x60, 0x80, 0x05, 0x61, 0x80, 0x05, 0x62, 0x80, 0x05, 0x63, 0x80, 0x18, 0x24, 0x03, 0x16,
71
    0x2c, 0x04, 0x13, 0x43, 0x53, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x53, 0x57, 0x43, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x30,
72
    0x30, 0x24, 0x05, 0x00, 0x24, 0x06, 0x00, 0x24, 0x07, 0x01, 0x24, 0x08, 0x00, 0x18, 0x31, 0x7e, 0x30, 0x7c, 0x02, 0x01, 0x03,
73
    0x80, 0x14, 0x62, 0xfa, 0x82, 0x33, 0x59, 0xac, 0xfa, 0xa9, 0x96, 0x3e, 0x1c, 0xfa, 0x14, 0x0a, 0xdd, 0xf5, 0x04, 0xf3, 0x71,
74
    0x60, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
75
    0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0x8d, 0xed, 0x3d, 0xdd, 0xbb, 0x6f, 0x3c, 0x6d, 0xca,
76
    0xc7, 0xb5, 0x75, 0x14, 0xc5, 0x8e, 0x69, 0x4a, 0xea, 0xd4, 0xc2, 0xc8, 0x2f, 0x9b, 0x46, 0x2b, 0x73, 0xeb, 0x00, 0x3a, 0x60,
77
    0x41, 0xf2, 0x02, 0x21, 0x00, 0xbd, 0x95, 0xe7, 0x9e, 0xe3, 0x8c, 0x07, 0x90, 0xd6, 0x9b, 0xaa, 0x45, 0x3b, 0xfc, 0x3c, 0x74,
78
    0x96, 0x6c, 0x79, 0x4f, 0x1c, 0x4d, 0xd7, 0x5d, 0x15, 0x03, 0x24, 0xd8, 0xa5, 0xca, 0x82, 0x3d
79
};
80
#elif CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID == 0xFFF3
81
constexpr const uint8_t kCdForAllExamples[] = {
82
    0x30, 0x82, 0x02, 0x17, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0x08, 0x30, 0x82,
83
    0x02, 0x04, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30,
84
    0x82, 0x01, 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x01, 0x61, 0x04, 0x82, 0x01,
85
    0x5d, 0x15, 0x24, 0x00, 0x01, 0x25, 0x01, 0xf3, 0xff, 0x36, 0x02, 0x05, 0x00, 0x80, 0x05, 0x01, 0x80, 0x05, 0x02, 0x80, 0x05,
86
    0x03, 0x80, 0x05, 0x04, 0x80, 0x05, 0x05, 0x80, 0x05, 0x06, 0x80, 0x05, 0x07, 0x80, 0x05, 0x08, 0x80, 0x05, 0x09, 0x80, 0x05,
87
    0x0a, 0x80, 0x05, 0x0b, 0x80, 0x05, 0x0c, 0x80, 0x05, 0x0d, 0x80, 0x05, 0x0e, 0x80, 0x05, 0x0f, 0x80, 0x05, 0x10, 0x80, 0x05,
88
    0x11, 0x80, 0x05, 0x12, 0x80, 0x05, 0x13, 0x80, 0x05, 0x14, 0x80, 0x05, 0x15, 0x80, 0x05, 0x16, 0x80, 0x05, 0x17, 0x80, 0x05,
89
    0x18, 0x80, 0x05, 0x19, 0x80, 0x05, 0x1a, 0x80, 0x05, 0x1b, 0x80, 0x05, 0x1c, 0x80, 0x05, 0x1d, 0x80, 0x05, 0x1e, 0x80, 0x05,
90
    0x1f, 0x80, 0x05, 0x20, 0x80, 0x05, 0x21, 0x80, 0x05, 0x22, 0x80, 0x05, 0x23, 0x80, 0x05, 0x24, 0x80, 0x05, 0x25, 0x80, 0x05,
91
    0x26, 0x80, 0x05, 0x27, 0x80, 0x05, 0x28, 0x80, 0x05, 0x29, 0x80, 0x05, 0x2a, 0x80, 0x05, 0x2b, 0x80, 0x05, 0x2c, 0x80, 0x05,
92
    0x2d, 0x80, 0x05, 0x2e, 0x80, 0x05, 0x2f, 0x80, 0x05, 0x30, 0x80, 0x05, 0x31, 0x80, 0x05, 0x32, 0x80, 0x05, 0x33, 0x80, 0x05,
93
    0x34, 0x80, 0x05, 0x35, 0x80, 0x05, 0x36, 0x80, 0x05, 0x37, 0x80, 0x05, 0x38, 0x80, 0x05, 0x39, 0x80, 0x05, 0x3a, 0x80, 0x05,
94
    0x3b, 0x80, 0x05, 0x3c, 0x80, 0x05, 0x3d, 0x80, 0x05, 0x3e, 0x80, 0x05, 0x3f, 0x80, 0x05, 0x40, 0x80, 0x05, 0x41, 0x80, 0x05,
95
    0x42, 0x80, 0x05, 0x43, 0x80, 0x05, 0x44, 0x80, 0x05, 0x45, 0x80, 0x05, 0x46, 0x80, 0x05, 0x47, 0x80, 0x05, 0x48, 0x80, 0x05,
96
    0x49, 0x80, 0x05, 0x4a, 0x80, 0x05, 0x4b, 0x80, 0x05, 0x4c, 0x80, 0x05, 0x4d, 0x80, 0x05, 0x4e, 0x80, 0x05, 0x4f, 0x80, 0x05,
97
    0x50, 0x80, 0x05, 0x51, 0x80, 0x05, 0x52, 0x80, 0x05, 0x53, 0x80, 0x05, 0x54, 0x80, 0x05, 0x55, 0x80, 0x05, 0x56, 0x80, 0x05,
98
    0x57, 0x80, 0x05, 0x58, 0x80, 0x05, 0x59, 0x80, 0x05, 0x5a, 0x80, 0x05, 0x5b, 0x80, 0x05, 0x5c, 0x80, 0x05, 0x5d, 0x80, 0x05,
99
    0x5e, 0x80, 0x05, 0x5f, 0x80, 0x05, 0x60, 0x80, 0x05, 0x61, 0x80, 0x05, 0x62, 0x80, 0x05, 0x63, 0x80, 0x18, 0x24, 0x03, 0x16,
100
    0x2c, 0x04, 0x13, 0x43, 0x53, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x53, 0x57, 0x43, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x30,
101
    0x30, 0x24, 0x05, 0x00, 0x24, 0x06, 0x00, 0x24, 0x07, 0x01, 0x24, 0x08, 0x00, 0x18, 0x31, 0x7c, 0x30, 0x7a, 0x02, 0x01, 0x03,
102
    0x80, 0x14, 0x62, 0xfa, 0x82, 0x33, 0x59, 0xac, 0xfa, 0xa9, 0x96, 0x3e, 0x1c, 0xfa, 0x14, 0x0a, 0xdd, 0xf5, 0x04, 0xf3, 0x71,
103
    0x60, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
104
    0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, 0x1e, 0x14, 0xa8, 0xc6, 0x95, 0x1d, 0x50, 0x87, 0x94, 0x2f,
105
    0x58, 0x69, 0x38, 0x8a, 0xdc, 0x49, 0x50, 0x40, 0x63, 0x5d, 0xdf, 0xc7, 0x93, 0x8b, 0xf0, 0x8a, 0x49, 0xce, 0x8f, 0xe2, 0xf0,
106
    0x28, 0x02, 0x20, 0x50, 0x90, 0x96, 0x20, 0x3f, 0xab, 0xe2, 0x19, 0xf8, 0xec, 0xf0, 0xe6, 0x9b, 0xa7, 0x51, 0x79, 0x9c, 0x02,
107
    0x98, 0x96, 0xc7, 0xc9, 0xc8, 0x2d, 0x4b, 0xf5, 0x76, 0xd3, 0x8f, 0xbd, 0x36, 0x5b
108
};
109
#else  /* Fall back to the VID=0xFFF1 CD */
110
constexpr const uint8_t kCdForAllExamples[] = {
111
    0x30, 0x82, 0x02, 0x17, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0x08, 0x30, 0x82,
112
    0x02, 0x04, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30,
113
    0x82, 0x01, 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x01, 0x61, 0x04, 0x82, 0x01,
114
    0x5d, 0x15, 0x24, 0x00, 0x01, 0x25, 0x01, 0xf1, 0xff, 0x36, 0x02, 0x05, 0x00, 0x80, 0x05, 0x01, 0x80, 0x05, 0x02, 0x80, 0x05,
115
    0x03, 0x80, 0x05, 0x04, 0x80, 0x05, 0x05, 0x80, 0x05, 0x06, 0x80, 0x05, 0x07, 0x80, 0x05, 0x08, 0x80, 0x05, 0x09, 0x80, 0x05,
116
    0x0a, 0x80, 0x05, 0x0b, 0x80, 0x05, 0x0c, 0x80, 0x05, 0x0d, 0x80, 0x05, 0x0e, 0x80, 0x05, 0x0f, 0x80, 0x05, 0x10, 0x80, 0x05,
117
    0x11, 0x80, 0x05, 0x12, 0x80, 0x05, 0x13, 0x80, 0x05, 0x14, 0x80, 0x05, 0x15, 0x80, 0x05, 0x16, 0x80, 0x05, 0x17, 0x80, 0x05,
118
    0x18, 0x80, 0x05, 0x19, 0x80, 0x05, 0x1a, 0x80, 0x05, 0x1b, 0x80, 0x05, 0x1c, 0x80, 0x05, 0x1d, 0x80, 0x05, 0x1e, 0x80, 0x05,
119
    0x1f, 0x80, 0x05, 0x20, 0x80, 0x05, 0x21, 0x80, 0x05, 0x22, 0x80, 0x05, 0x23, 0x80, 0x05, 0x24, 0x80, 0x05, 0x25, 0x80, 0x05,
120
    0x26, 0x80, 0x05, 0x27, 0x80, 0x05, 0x28, 0x80, 0x05, 0x29, 0x80, 0x05, 0x2a, 0x80, 0x05, 0x2b, 0x80, 0x05, 0x2c, 0x80, 0x05,
121
    0x2d, 0x80, 0x05, 0x2e, 0x80, 0x05, 0x2f, 0x80, 0x05, 0x30, 0x80, 0x05, 0x31, 0x80, 0x05, 0x32, 0x80, 0x05, 0x33, 0x80, 0x05,
122
    0x34, 0x80, 0x05, 0x35, 0x80, 0x05, 0x36, 0x80, 0x05, 0x37, 0x80, 0x05, 0x38, 0x80, 0x05, 0x39, 0x80, 0x05, 0x3a, 0x80, 0x05,
123
    0x3b, 0x80, 0x05, 0x3c, 0x80, 0x05, 0x3d, 0x80, 0x05, 0x3e, 0x80, 0x05, 0x3f, 0x80, 0x05, 0x40, 0x80, 0x05, 0x41, 0x80, 0x05,
124
    0x42, 0x80, 0x05, 0x43, 0x80, 0x05, 0x44, 0x80, 0x05, 0x45, 0x80, 0x05, 0x46, 0x80, 0x05, 0x47, 0x80, 0x05, 0x48, 0x80, 0x05,
125
    0x49, 0x80, 0x05, 0x4a, 0x80, 0x05, 0x4b, 0x80, 0x05, 0x4c, 0x80, 0x05, 0x4d, 0x80, 0x05, 0x4e, 0x80, 0x05, 0x4f, 0x80, 0x05,
126
    0x50, 0x80, 0x05, 0x51, 0x80, 0x05, 0x52, 0x80, 0x05, 0x53, 0x80, 0x05, 0x54, 0x80, 0x05, 0x55, 0x80, 0x05, 0x56, 0x80, 0x05,
127
    0x57, 0x80, 0x05, 0x58, 0x80, 0x05, 0x59, 0x80, 0x05, 0x5a, 0x80, 0x05, 0x5b, 0x80, 0x05, 0x5c, 0x80, 0x05, 0x5d, 0x80, 0x05,
128
    0x5e, 0x80, 0x05, 0x5f, 0x80, 0x05, 0x60, 0x80, 0x05, 0x61, 0x80, 0x05, 0x62, 0x80, 0x05, 0x63, 0x80, 0x18, 0x24, 0x03, 0x16,
129
    0x2c, 0x04, 0x13, 0x43, 0x53, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x53, 0x57, 0x43, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x30,
130
    0x30, 0x24, 0x05, 0x00, 0x24, 0x06, 0x00, 0x24, 0x07, 0x01, 0x24, 0x08, 0x00, 0x18, 0x31, 0x7c, 0x30, 0x7a, 0x02, 0x01, 0x03,
131
    0x80, 0x14, 0xfe, 0x34, 0x3f, 0x95, 0x99, 0x47, 0x76, 0x3b, 0x61, 0xee, 0x45, 0x39, 0x13, 0x13, 0x38, 0x49, 0x4f, 0xe6, 0x7d,
132
    0x8e, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
133
    0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, 0x4a, 0x12, 0xf8, 0xd4, 0x2f, 0x90, 0x23, 0x5c, 0x05, 0xa7,
134
    0x71, 0x21, 0xcb, 0xeb, 0xae, 0x15, 0xd5, 0x90, 0x14, 0x65, 0x58, 0xe9, 0xc9, 0xb4, 0x7a, 0x1a, 0x38, 0xf7, 0xa3, 0x6a, 0x7d,
135
    0xc5, 0x02, 0x20, 0x20, 0xa4, 0x74, 0x28, 0x97, 0xc3, 0x0a, 0xed, 0xa0, 0xa5, 0x6b, 0x36, 0xe1, 0x4e, 0xbb, 0xc8, 0x5b, 0xbd,
136
    0xb7, 0x44, 0x93, 0xf9, 0x93, 0x58, 0x1e, 0xb0, 0x44, 0x4e, 0xd6, 0xca, 0x94, 0x0b
137
};
138
#endif // CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID
139
140
namespace chip {
141
namespace Credentials {
142
namespace Examples {
143
144
namespace {
145
146
CHIP_ERROR ReadJsonString(const Json::Value & value, CharSpan & out)
147
0
{
148
0
    const char * begin;
149
0
    const char * end;
150
0
    VerifyOrReturnError(value.getString(&begin, &end), CHIP_ERROR_INVALID_ARGUMENT);
151
0
    out = CharSpan(begin, static_cast<size_t>(end - begin));
152
0
    return CHIP_NO_ERROR;
153
0
}
154
155
bool ReadValue(Json::Value jsonValue)
156
0
{
157
0
    const std::string value = jsonValue.asString();
158
0
    if (strcmp(value.c_str(), "true") == 0)
159
0
    {
160
0
        return true;
161
0
    }
162
0
    return false;
163
0
}
164
165
ByteSpan GetProfileDocument(DeviceAttestationCertProfile profile, ByteSpan legacy, ByteSpan pqc44, ByteSpan pqc65)
166
0
{
167
0
    switch (profile)
168
0
    {
169
0
    case DeviceAttestationCertProfile::kEcdsaMatterLegacy:
170
0
        return legacy;
171
0
    case DeviceAttestationCertProfile::kMlDsa44:
172
0
        return pqc44;
173
0
    case DeviceAttestationCertProfile::kMlDsa65:
174
0
        return pqc65;
175
0
    case DeviceAttestationCertProfile::kUnknownEnumValue:
176
0
        return ByteSpan();
177
0
    }
178
179
0
    return ByteSpan();
180
0
}
181
182
BitMask<DeviceAttestationCertProfileBitmap> BuildProfileSupport(ByteSpan legacy, ByteSpan pqc44, ByteSpan pqc65)
183
0
{
184
0
    using SupportMask = BitMask<DeviceAttestationCertProfileBitmap>;
185
0
    SupportMask support(0);
186
187
0
    if (!legacy.empty())
188
0
    {
189
0
        support = SupportMask(
190
0
            support.Raw() | static_cast<SupportMask::IntegerType>(DeviceAttestationCertProfileBitmap::kSupportsEcdsaMatterLegacy));
191
0
    }
192
0
    if (!pqc44.empty())
193
0
    {
194
0
        support = SupportMask(support.Raw() |
195
0
                              static_cast<SupportMask::IntegerType>(DeviceAttestationCertProfileBitmap::kSupportsMlDsa44));
196
0
    }
197
0
    if (!pqc65.empty())
198
0
    {
199
0
        support = SupportMask(support.Raw() |
200
0
                              static_cast<SupportMask::IntegerType>(DeviceAttestationCertProfileBitmap::kSupportsMlDsa65));
201
0
    }
202
203
0
    return support;
204
0
}
205
206
CHIP_ERROR CopyDocumentSegment(ByteSpan document, size_t offset, MutableByteSpan & outBuffer, size_t & outDocumentSize)
207
0
{
208
0
    VerifyOrReturnError(offset < document.size(), CHIP_ERROR_INVALID_ARGUMENT);
209
0
    const size_t segmentSize = std::min(outBuffer.size(), document.size() - offset);
210
0
    outDocumentSize          = document.size();
211
0
    return CopySpanToMutableSpan(document.SubSpan(offset, segmentSize), outBuffer);
212
0
}
213
214
} // namespace
215
216
TestHarnessDACProvider::TestHarnessDACProvider()
217
0
{
218
0
    TestHarnessDACProviderData data;
219
0
    Init(data);
220
0
}
221
222
void TestHarnessDACProvider::Init(const char * filepath)
223
0
{
224
0
    std::ifstream json(filepath, std::ifstream::binary);
225
0
    if (!json)
226
0
    {
227
0
        ChipLogError(AppServer, "Error opening json file: %s", StringOrNullMarker(filepath));
228
0
        return;
229
0
    }
230
231
    // Preserve the file-based API while sharing JSON parsing with in-memory callers.
232
0
    CHIP_ERROR err = Init(json);
233
0
    if (err != CHIP_NO_ERROR)
234
0
    {
235
0
        ChipLogError(AppServer, "Error parsing json file: %s: %" CHIP_ERROR_FORMAT, StringOrNullMarker(filepath), err.Format());
236
0
    }
237
0
}
238
239
CHIP_ERROR TestHarnessDACProvider::Init(std::istream & json)
240
0
{
241
0
    Json::Reader reader;
242
0
    Json::Value root;
243
0
    VerifyOrReturnError(reader.parse(json, root) && root.isObject(), CHIP_ERROR_INVALID_ARGUMENT);
244
245
0
    TestHarnessDACProviderData data;
246
247
0
    auto readPaiProfile = [](const Json::Value & value, DeviceAttestationCertProfile & outProfile) -> CHIP_ERROR {
248
0
        VerifyOrReturnError(value.isIntegral() && value.isUInt(), CHIP_ERROR_INVALID_ARGUMENT);
249
0
        const auto raw = value.asUInt();
250
0
        VerifyOrReturnError(raw == static_cast<unsigned>(DeviceAttestationCertProfile::kEcdsaMatterLegacy) ||
251
0
                                raw == static_cast<unsigned>(DeviceAttestationCertProfile::kMlDsa44) ||
252
0
                                raw == static_cast<unsigned>(DeviceAttestationCertProfile::kMlDsa65),
253
0
                            CHIP_ERROR_INVALID_ARGUMENT);
254
0
        outProfile = static_cast<DeviceAttestationCertProfile>(raw);
255
0
        return CHIP_NO_ERROR;
256
0
    };
257
0
    if (root.isMember("pai_profile_ml_dsa_44"))
258
0
    {
259
0
        ReturnErrorOnFailure(readPaiProfile(root["pai_profile_ml_dsa_44"], data.paiProfileMlDsa44));
260
0
    }
261
0
    if (root.isMember("pai_profile_ml_dsa_65"))
262
0
    {
263
0
        ReturnErrorOnFailure(readPaiProfile(root["pai_profile_ml_dsa_65"], data.paiProfileMlDsa65));
264
0
    }
265
266
0
    struct HexField
267
0
    {
268
0
        const char * key;
269
0
        size_t maxSize;
270
0
        Optional<ByteSpan> & destination;
271
0
        CharSpan hex;
272
0
    };
273
0
    HexField fields[] = {
274
0
        { "dac_cert", kMaxDERCertLength, data.dacCert },
275
0
        { "dac_private_key", Crypto::kP256_PrivateKey_Length, data.dacPrivateKey },
276
0
        { "dac_public_key", Crypto::kP256_PublicKey_Length, data.dacPublicKey },
277
0
        { "dac_cert_ml_dsa_44", kMaxDERCertLengthMlDsa44, data.pqcDacCertMlDsa44 },
278
0
        { "dac_cert_ml_dsa_65", kMaxDERCertLengthMlDsa65, data.pqcDacCertMlDsa65 },
279
0
        { "pai_cert", kMaxDERCertLength, data.paiCert },
280
0
        { "pai_cert_ml_dsa_44", kMaxDERCertLengthMlDsa44, data.pqcPaiCertMlDsa44 },
281
0
        { "pai_cert_ml_dsa_65", kMaxDERCertLengthMlDsa65, data.pqcPaiCertMlDsa65 },
282
0
        { "certification_declaration", kMaxCMSSignedCDMessage, data.certificationDeclaration },
283
0
        { "firmware_information", UINT8_MAX, data.firmwareInformation },
284
0
    };
285
286
    // Bound and validate every field before allocating the decoded fixture. JsonCpp
287
    // owns the strings referenced by hex/description until this method returns.
288
0
    size_t storageSize = 0;
289
0
    for (auto & field : fields)
290
0
    {
291
0
        if (!root.isMember(field.key))
292
0
        {
293
0
            continue;
294
0
        }
295
0
        ReturnErrorOnFailure(ReadJsonString(root[field.key], field.hex));
296
0
        VerifyOrReturnError(field.hex.size() % 2 == 0, CHIP_ERROR_INVALID_ARGUMENT);
297
0
        VerifyOrReturnError(field.hex.size() / 2 <= field.maxSize, CHIP_ERROR_INVALID_ARGUMENT);
298
0
        for (char c : field.hex)
299
0
        {
300
0
            VerifyOrReturnError((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'),
301
0
                                CHIP_ERROR_INVALID_ARGUMENT);
302
0
        }
303
0
        storageSize += field.hex.size() / 2;
304
0
    }
305
306
0
    CharSpan description;
307
0
    if (root.isMember("description"))
308
0
    {
309
0
        ReturnErrorOnFailure(ReadJsonString(root["description"], description));
310
        // The former 256-byte buffer reserved one byte for a null terminator.
311
0
        VerifyOrReturnError(description.size() <= 255, CHIP_ERROR_INVALID_ARGUMENT);
312
0
        storageSize += description.size();
313
0
    }
314
0
    if (root.isMember("is_success_case"))
315
0
    {
316
0
        VerifyOrReturnError(root["is_success_case"].isBool() || root["is_success_case"].isString(), CHIP_ERROR_INVALID_ARGUMENT);
317
0
        data.isSuccessCase.SetValue(ReadValue(root["is_success_case"]));
318
0
    }
319
0
    if (root.isMember("basic_info_pid"))
320
0
    {
321
0
        const auto & pid = root["basic_info_pid"];
322
0
        VerifyOrReturnError(pid.isIntegral() && pid.isUInt() && pid.asUInt() <= UINT16_MAX, CHIP_ERROR_INVALID_ARGUMENT);
323
0
        data.pid.SetValue(static_cast<uint16_t>(pid.asUInt()));
324
0
    }
325
326
0
    Platform::ScopedMemoryBuffer<uint8_t> storage;
327
0
    VerifyOrReturnError(storageSize == 0 || storage.Alloc(storageSize), CHIP_ERROR_NO_MEMORY);
328
0
    size_t offset = 0;
329
0
    for (auto & field : fields)
330
0
    {
331
0
        if (!root.isMember(field.key))
332
0
        {
333
0
            continue;
334
0
        }
335
0
        const size_t size = field.hex.size() / 2;
336
0
        ByteSpan bytes;
337
0
        if (size != 0)
338
0
        {
339
0
            uint8_t * dest = storage.Get() + offset;
340
0
            VerifyOrReturnError(Encoding::HexToBytes(field.hex.data(), field.hex.size(), dest, size) == size,
341
0
                                CHIP_ERROR_INVALID_ARGUMENT);
342
0
            bytes = ByteSpan(dest, size);
343
0
            offset += size;
344
0
        }
345
0
        field.destination.SetValue(bytes);
346
0
    }
347
0
    if (root.isMember("description"))
348
0
    {
349
0
        CharSpan ownedDescription;
350
0
        if (!description.empty())
351
0
        {
352
0
            auto * dest = reinterpret_cast<char *>(storage.Get() + offset);
353
0
            memcpy(dest, description.data(), description.size());
354
0
            ownedDescription = CharSpan(dest, description.size());
355
0
        }
356
0
        data.description.SetValue(ownedDescription);
357
0
    }
358
359
0
    Init(data);
360
0
    mJsonStorage = std::move(storage);
361
0
    return CHIP_NO_ERROR;
362
0
}
363
364
void TestHarnessDACProvider::Init(const TestHarnessDACProviderData & data)
365
0
{
366
0
    mJsonStorage.Free();
367
0
    mDacCert       = data.dacCert.HasValue() ? data.dacCert.Value() : DevelopmentCerts::kDacCert;
368
0
    mDacPrivateKey = data.dacPrivateKey.HasValue() ? data.dacPrivateKey.Value() : DevelopmentCerts::kDacPrivateKey;
369
0
    mDacPublicKey  = data.dacPublicKey.HasValue() ? data.dacPublicKey.Value() : DevelopmentCerts::kDacPublicKey;
370
0
    mPaiCert       = data.paiCert.HasValue() ? data.paiCert.Value() : DevelopmentCerts::kPaiCert;
371
372
0
    mPqcDacCertMlDsa44 = data.pqcDacCertMlDsa44.HasValue() ? data.pqcDacCertMlDsa44.Value() : ByteSpan();
373
0
    mPqcDacCertMlDsa65 = data.pqcDacCertMlDsa65.HasValue() ? data.pqcDacCertMlDsa65.Value() : ByteSpan();
374
375
0
    mPqcPaiCertMlDsa44 = data.pqcPaiCertMlDsa44.HasValue() ? data.pqcPaiCertMlDsa44.Value() : ByteSpan();
376
0
    mPqcPaiCertMlDsa65 = data.pqcPaiCertMlDsa65.HasValue() ? data.pqcPaiCertMlDsa65.Value() : ByteSpan();
377
378
0
    mCertificationDeclaration =
379
0
        data.certificationDeclaration.HasValue() ? data.certificationDeclaration.Value() : ByteSpan{ kCdForAllExamples };
380
0
    mIsSuccessCase = data.isSuccessCase.HasValue() ? data.isSuccessCase.Value() : true;
381
0
    mDescription   = data.description.HasValue() ? data.description.Value() : CharSpan();
382
383
    // TODO: We need a real example FirmwareInformation to be populated.
384
0
    mFirmwareInformation = data.firmwareInformation.HasValue() ? data.firmwareInformation.Value() : ByteSpan();
385
386
0
    mPid = data.pid.ValueOr(0x8000);
387
388
    // Only complete pairs can be selected. In particular, do not mix a DAC from
389
    // one chain with a PAI from a different chain when a fixture is incomplete.
390
0
    const bool has44 = !mPqcPaiCertMlDsa44.empty() && !mPqcDacCertMlDsa44.empty();
391
0
    const bool has65 = !mPqcPaiCertMlDsa65.empty() && !mPqcDacCertMlDsa65.empty();
392
    // The storage suffix declares the PAA algorithm for that chain. It does not
393
    // describe the PAI's own key: pai_profile_ml_dsa_44/65 declare that separately.
394
    // For example, a complete _ml_dsa_65 pair with pai_profile_ml_dsa_65 = 0
395
    // contributes ML-DSA-65 to PAA support and only ECDSA to PAI/DAC support.
396
0
    mProfileSupport = {
397
0
        .PAASupportedProfiles =
398
0
            BuildProfileSupport(mPaiCert, has44 ? mPqcPaiCertMlDsa44 : ByteSpan(), has65 ? mPqcPaiCertMlDsa65 : ByteSpan()),
399
0
        .PAISupportedProfiles = BuildProfileSupport(mPaiCert, ByteSpan(), ByteSpan()),
400
0
        .DACSupportedProfiles = BuildProfileSupport(mDacCert, ByteSpan(), ByteSpan()),
401
0
    };
402
0
    auto addPaiProfile = [this](DeviceAttestationCertProfile profile) {
403
0
        switch (profile)
404
0
        {
405
0
        case DeviceAttestationCertProfile::kEcdsaMatterLegacy:
406
0
            mProfileSupport.PAISupportedProfiles.Set(DeviceAttestationCertProfileBitmap::kSupportsEcdsaMatterLegacy);
407
0
            break;
408
0
        case DeviceAttestationCertProfile::kMlDsa44:
409
0
            mProfileSupport.PAISupportedProfiles.Set(DeviceAttestationCertProfileBitmap::kSupportsMlDsa44);
410
0
            break;
411
0
        case DeviceAttestationCertProfile::kMlDsa65:
412
0
            mProfileSupport.PAISupportedProfiles.Set(DeviceAttestationCertProfileBitmap::kSupportsMlDsa65);
413
0
            break;
414
0
        case DeviceAttestationCertProfile::kUnknownEnumValue:
415
0
            break;
416
0
        }
417
0
    };
418
0
    if (has44)
419
0
    {
420
0
        addPaiProfile(data.paiProfileMlDsa44);
421
0
    }
422
0
    if (has65)
423
0
    {
424
0
        addPaiProfile(data.paiProfileMlDsa65);
425
0
    }
426
0
}
427
428
CHIP_ERROR TestHarnessDACProvider::GetDeviceAttestationCert(MutableByteSpan & out_dac_buffer)
429
0
{
430
0
    return CopySpanToMutableSpan(mDacCert, out_dac_buffer);
431
0
}
432
433
CHIP_ERROR TestHarnessDACProvider::GetDeviceAttestationCertForProfile(DeviceAttestationCertProfile profile,
434
                                                                      MutableByteSpan & out_dac_buffer)
435
0
{
436
0
    ByteSpan document = GetProfileDocument(profile, mDacCert, mPqcDacCertMlDsa44, mPqcDacCertMlDsa65);
437
0
    VerifyOrReturnError(!document.empty(), CHIP_ERROR_NOT_IMPLEMENTED);
438
0
    return CopySpanToMutableSpan(document, out_dac_buffer);
439
0
}
440
441
CHIP_ERROR TestHarnessDACProvider::GetProductAttestationIntermediateCert(MutableByteSpan & out_pai_buffer)
442
0
{
443
0
    return CopySpanToMutableSpan(mPaiCert, out_pai_buffer);
444
0
}
445
446
CHIP_ERROR TestHarnessDACProvider::GetProductAttestationIntermediateCertForProfile(DeviceAttestationCertProfile profile,
447
                                                                                   MutableByteSpan & out_pai_buffer)
448
0
{
449
0
    ByteSpan document = GetProfileDocument(profile, mPaiCert, mPqcPaiCertMlDsa44, mPqcPaiCertMlDsa65);
450
0
    VerifyOrReturnError(!document.empty(), CHIP_ERROR_NOT_IMPLEMENTED);
451
0
    return CopySpanToMutableSpan(document, out_pai_buffer);
452
0
}
453
454
CHIP_ERROR TestHarnessDACProvider::GetCertificationDeclaration(MutableByteSpan & out_cd_buffer)
455
0
{
456
0
    return CopySpanToMutableSpan(mCertificationDeclaration, out_cd_buffer);
457
0
}
458
459
CHIP_ERROR TestHarnessDACProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer)
460
0
{
461
0
    return CopySpanToMutableSpan(mFirmwareInformation, out_firmware_info_buffer);
462
0
}
463
464
CHIP_ERROR TestHarnessDACProvider::SignWithDeviceAttestationKey(const ByteSpan & message_to_sign,
465
                                                                MutableByteSpan & out_signature_buffer)
466
0
{
467
0
    Crypto::P256ECDSASignature signature;
468
0
    Crypto::P256Keypair keypair;
469
470
0
    VerifyOrReturnError(!out_signature_buffer.empty(), CHIP_ERROR_INVALID_ARGUMENT);
471
0
    VerifyOrReturnError(!message_to_sign.empty(), CHIP_ERROR_INVALID_ARGUMENT);
472
0
    VerifyOrReturnError(out_signature_buffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL);
473
    // In a non-exemplary implementation, the public key is not needed here. It is used here merely because
474
    // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present.
475
0
    ReturnErrorOnFailure(keypair.HazardousOperationLoadKeypairFromRaw(mDacPrivateKey, mDacPublicKey));
476
0
    ReturnErrorOnFailure(keypair.ECDSA_sign_msg(message_to_sign.data(), message_to_sign.size(), signature));
477
478
0
    return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, out_signature_buffer);
479
0
}
480
481
DeviceAttestationProfileSupport TestHarnessDACProvider::GetDeviceAttestationProfileSupport() const
482
0
{
483
0
    return mProfileSupport;
484
0
}
485
486
DeviceAttestationCertProfile TestHarnessDACProvider::GetPreferredDeviceAttestationChainProfile() const
487
0
{
488
0
    if (!mPqcPaiCertMlDsa65.empty() && !mPqcDacCertMlDsa65.empty())
489
0
    {
490
0
        return DeviceAttestationCertProfile::kMlDsa65;
491
0
    }
492
0
    if (!mPqcPaiCertMlDsa44.empty() && !mPqcDacCertMlDsa44.empty())
493
0
    {
494
0
        return DeviceAttestationCertProfile::kMlDsa44;
495
0
    }
496
0
    return DeviceAttestationCertProfile::kEcdsaMatterLegacy;
497
0
}
498
499
CHIP_ERROR TestHarnessDACProvider::GetDeviceAttestationDocumentSegment(DeviceAttestationDocumentType documentType,
500
                                                                       DeviceAttestationCertProfile profile, size_t offset,
501
                                                                       MutableByteSpan & out_document_buffer,
502
                                                                       size_t & out_document_size)
503
0
{
504
0
    ByteSpan document;
505
0
    switch (documentType)
506
0
    {
507
0
    case DeviceAttestationDocumentType::kDACCertificate:
508
0
        document = GetProfileDocument(profile, mDacCert, mPqcDacCertMlDsa44, mPqcDacCertMlDsa65);
509
0
        break;
510
0
    case DeviceAttestationDocumentType::kPAICertificate:
511
0
        document = GetProfileDocument(profile, mPaiCert, mPqcPaiCertMlDsa44, mPqcPaiCertMlDsa65);
512
0
        break;
513
0
    default:
514
0
        return CHIP_ERROR_INVALID_ARGUMENT;
515
0
    }
516
517
0
    VerifyOrReturnError(!document.empty(), CHIP_ERROR_NOT_IMPLEMENTED);
518
0
    return CopyDocumentSegment(document, offset, out_document_buffer, out_document_size);
519
0
}
520
521
} // namespace Examples
522
} // namespace Credentials
523
} // namespace chip