Coverage Report

Created: 2025-08-28 06:31

/src/connectedhomeip/examples/common/tracing/decoder/logging/ToCertificateString.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *   Copyright (c) 2022 Project CHIP Authors
3
 *   All rights reserved.
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
 */
18
19
#include "ToCertificateString.h"
20
21
#include <lib/support/Base64.h>
22
#include <lib/support/SafeInt.h>
23
#include <lib/support/ScopedBuffer.h>
24
25
namespace {
26
constexpr const uint8_t kChipRawPrefix[] = { 0x15, 0x30, 0x01 };
27
28
bool IsChipCertificate(const chip::ByteSpan & source)
29
0
{
30
0
    return (source.size() > sizeof(kChipRawPrefix)) && (memcmp(source.data(), kChipRawPrefix, sizeof(kChipRawPrefix)) == 0);
31
0
}
32
33
const char * ToCertificate(const chip::ByteSpan & source, chip::MutableCharSpan destination, const char * header = "",
34
                           const char * footer = "")
35
0
{
36
    // Reset the buffer
37
0
    memset(destination.data(), '\0', destination.size());
38
0
    int snprintf_len = 0;
39
0
    if (source.size() == 0)
40
0
    {
41
0
        return destination.data();
42
0
    }
43
44
0
    if (!chip::CanCastTo<uint16_t>(source.size()))
45
0
    {
46
0
        ChipLogError(DataManagement, "The certificate is too large to do base64 conversion on");
47
0
        return destination.data();
48
0
    }
49
50
0
    size_t base64DataLen = BASE64_ENCODED_LEN(source.size());
51
0
    size_t bufferLen     = base64DataLen + 1; // add one character for null-terminator
52
0
    if (bufferLen + strlen(header) + strlen(footer) > destination.size())
53
0
    {
54
0
        ChipLogError(DataManagement, "The certificate buffer is too small to hold the base64 encoded certificate");
55
0
        return destination.data();
56
0
    }
57
58
0
    chip::Platform::ScopedMemoryBuffer<char> str;
59
0
    str.Alloc(bufferLen);
60
61
0
    auto encodedLen       = chip::Base64Encode(source.data(), static_cast<uint16_t>(source.size()), str.Get());
62
0
    str.Get()[encodedLen] = '\0';
63
64
0
    if (IsChipCertificate(source))
65
0
    {
66
        // Wherever Matter Operational Certificate Encoding representation is used, all certificates SHALL NOT be longer than 400
67
        // bytes in their TLV form.
68
0
        if (source.size() > 400)
69
0
        {
70
0
            ChipLogError(DataManagement, "Certificate size is greater than 400 bytes");
71
0
        }
72
73
0
        snprintf_len = snprintf(destination.data(), destination.size(), "%s", str.Get());
74
0
        VerifyOrExit(snprintf_len >= 0, ChipLogError(DataManagement, "Failed to write certificate"););
75
0
    }
76
0
    else
77
0
    {
78
        // All certificates SHALL NOT be longer than 600 bytes in their uncompressed DER format.
79
0
        if (source.size() > 600)
80
0
        {
81
0
            ChipLogError(DataManagement, "Certificate size is greater than 600 bytes");
82
0
        }
83
84
0
        size_t inIndex  = 0;
85
0
        size_t outIndex = strlen(header) + 1;
86
87
0
        snprintf_len = snprintf(destination.data(), destination.size(), "%s\n", header);
88
0
        VerifyOrExit(snprintf_len >= 0, ChipLogError(DataManagement, "Failed to write header"););
89
0
        for (; inIndex < base64DataLen; inIndex += 64)
90
0
        {
91
0
            snprintf_len = snprintf(&destination.data()[outIndex], destination.size() - outIndex, "%.64s\n", &str[inIndex]);
92
0
            VerifyOrExit(snprintf_len >= 0, ChipLogError(DataManagement, "Failed to write certificate"););
93
94
0
            outIndex += static_cast<size_t>(snprintf_len);
95
0
        }
96
0
        snprintf_len = snprintf(&destination.data()[outIndex], destination.size() - outIndex, "%s", footer);
97
0
        VerifyOrExit(snprintf_len >= 0, ChipLogError(DataManagement, "Failed to write footer"););
98
0
    }
99
0
exit:
100
0
    if (snprintf_len < 0)
101
0
    {
102
0
        memset(destination.data(), '\0', destination.size());
103
0
    }
104
0
    return destination.data();
105
0
}
106
107
} // namespace
108
109
namespace chip {
110
namespace trace {
111
namespace logging {
112
113
const char * ToCertificateString(const ByteSpan & source, MutableCharSpan destination)
114
0
{
115
0
    static constexpr char kCertificateHeader[] = "-----BEGIN CERTIFICATE-----";
116
0
    static constexpr char kCertificateFooter[] = "-----END CERTIFICATE-----";
117
118
0
    return ToCertificate(source, destination, kCertificateHeader, kCertificateFooter);
119
0
}
120
121
const char * ToCertificateRequestString(const ByteSpan & source, MutableCharSpan destination)
122
0
{
123
0
    static constexpr char kCertificateHeader[] = "-----BEGIN CERTIFICATE REQUEST-----";
124
0
    static constexpr char kCertificateFooter[] = "-----END CERTIFICATE REQUEST-----";
125
126
0
    return ToCertificate(source, destination, kCertificateHeader, kCertificateFooter);
127
0
}
128
129
} // namespace logging
130
} // namespace trace
131
} // namespace chip