/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 |