Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-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 :
18 : /**
19 : * @file
20 : * Platform agnostic implementation of CHIP crypto algorithms
21 : */
22 :
23 : #include "CHIPCryptoPAL.h"
24 :
25 : #include "SessionKeystore.h"
26 :
27 : #include <lib/asn1/ASN1.h>
28 : #include <lib/asn1/ASN1Macros.h>
29 : #include <lib/core/CHIPEncoding.h>
30 : #include <lib/support/Base64.h>
31 : #include <lib/support/BufferReader.h>
32 : #include <lib/support/BufferWriter.h>
33 : #include <lib/support/BytesToHex.h>
34 : #include <lib/support/CHIPMemString.h>
35 : #include <lib/support/CodeUtils.h>
36 : #include <lib/support/Span.h>
37 : #include <lib/support/StringBuilder.h>
38 : #include <lib/support/TypeTraits.h>
39 : #include <stdint.h>
40 : #include <string.h>
41 :
42 : using chip::ByteSpan;
43 : using chip::MutableByteSpan;
44 : using chip::Encoding::BufferWriter;
45 : using chip::Encoding::LittleEndian::Reader;
46 :
47 : using namespace chip::ASN1;
48 :
49 : namespace chip {
50 : namespace Crypto {
51 : namespace {
52 :
53 : constexpr uint8_t kIntegerTag = 0x02u;
54 : constexpr uint8_t kSeqTag = 0x30u;
55 : constexpr size_t kMinSequenceOverhead = 1 /* tag */ + 1 /* length */ + 1 /* actual data or second length byte*/;
56 :
57 : /**
58 : * @brief Utility to convert DER-encoded INTEGER into a raw integer buffer in big-endian order
59 : * with leading zeroes if the output buffer is larger than needed.
60 : * @param[in] reader Reader instance from which the input will be read
61 : * @param[out] raw_integer_out Buffer to receive the DER-encoded integer
62 : * @return CHIP_ERROR_INVALID_ARGUMENT or CHIP_ERROR_BUFFER_TOO_SMALL on error, CHIP_NO_ERROR otherwise
63 : */
64 368 : CHIP_ERROR ReadDerUnsignedIntegerIntoRaw(Reader & reader, MutableByteSpan raw_integer_out)
65 : {
66 368 : uint8_t cur_byte = 0;
67 :
68 368 : ReturnErrorOnFailure(reader.Read8(&cur_byte).StatusCode());
69 :
70 : // We expect first tag to be INTEGER
71 368 : VerifyOrReturnError(cur_byte == kIntegerTag, CHIP_ERROR_INVALID_ARGUMENT);
72 :
73 : // Read the length
74 368 : size_t integer_len = 0;
75 368 : ReturnErrorOnFailure(chip::Crypto::ReadDerLength(reader, integer_len));
76 :
77 : // Clear the destination buffer, so we can blit the unsigned value into place
78 368 : memset(raw_integer_out.data(), 0, raw_integer_out.size());
79 :
80 : // Check for pseudo-zero to mark unsigned value
81 : // This means we have too large an integer (should be at most 1 byte too large), it's invalid
82 368 : VerifyOrReturnError(integer_len <= (raw_integer_out.size() + 1), CHIP_ERROR_INVALID_ARGUMENT);
83 :
84 368 : if (integer_len == (raw_integer_out.size() + 1u))
85 : {
86 : // Means we had a 0x00 byte stuffed due to MSB being high in original integer
87 207 : ReturnErrorOnFailure(reader.Read8(&cur_byte).StatusCode());
88 :
89 : // The extra byte must be a leading zero
90 207 : VerifyOrReturnError(cur_byte == 0, CHIP_ERROR_INVALID_ARGUMENT);
91 207 : --integer_len;
92 : }
93 :
94 : // We now have the rest of the tag that is a "minimal length" unsigned integer.
95 : // Blit it at the correct offset, since the order we use is MSB first for
96 : // both ASN.1 and EC curve raw points.
97 368 : size_t offset = raw_integer_out.size() - integer_len;
98 368 : return reader.ReadBytes(raw_integer_out.data() + offset, integer_len).StatusCode();
99 : }
100 :
101 285 : CHIP_ERROR ConvertIntegerRawToDerInternal(const ByteSpan & raw_integer, MutableByteSpan & out_der_integer,
102 : bool include_tag_and_length)
103 : {
104 285 : if (raw_integer.empty() || out_der_integer.empty())
105 : {
106 2 : return CHIP_ERROR_INVALID_ARGUMENT;
107 : }
108 :
109 283 : Reader reader(raw_integer);
110 283 : BufferWriter writer(out_der_integer);
111 :
112 283 : bool needs_leading_zero_byte = false;
113 :
114 283 : uint8_t cur_byte = 0;
115 469 : while ((reader.Remaining() > 0) && (reader.Read8(&cur_byte).StatusCode() == CHIP_NO_ERROR) && (cur_byte == 0))
116 : {
117 : // Omit all leading zeros
118 : }
119 :
120 283 : if ((cur_byte & 0x80u) != 0)
121 : {
122 : // If overall MSB (from leftmost byte) is set, we will need to push out a zero to avoid it being
123 : // considered a negative number.
124 137 : needs_leading_zero_byte = true;
125 : }
126 :
127 : // The + 1 is to account for the last consumed byte of the loop to skip leading zeros
128 283 : size_t length = reader.Remaining() + 1 + (needs_leading_zero_byte ? 1 : 0);
129 :
130 283 : if (length > 127)
131 : {
132 : // We do not support length over more than 1 bytes.
133 0 : return CHIP_ERROR_INVALID_ARGUMENT;
134 : }
135 :
136 283 : if (include_tag_and_length)
137 : {
138 : // Put INTEGER tag
139 24 : writer.Put(kIntegerTag);
140 :
141 : // Put length over 1 byte (i.e. MSB clear)
142 24 : writer.Put(static_cast<uint8_t>(length));
143 : }
144 :
145 : // If leading zero or no more bytes remaining, must ensure we start with at least a zero byte
146 283 : if (needs_leading_zero_byte)
147 : {
148 137 : writer.Put(static_cast<uint8_t>(0u));
149 : }
150 :
151 : // Put first consumed byte from last read iteration of leading zero suppression
152 283 : writer.Put(cur_byte);
153 :
154 : // Fill the rest from the input in order
155 8406 : while (reader.Read8(&cur_byte).StatusCode() == CHIP_NO_ERROR)
156 : {
157 : // Emit all other bytes as-is
158 8123 : writer.Put(cur_byte);
159 : }
160 :
161 283 : size_t actually_written = 0;
162 283 : if (!writer.Fit(actually_written))
163 : {
164 7 : return CHIP_ERROR_BUFFER_TOO_SMALL;
165 : }
166 :
167 276 : out_der_integer = out_der_integer.SubSpan(0, actually_written);
168 :
169 276 : return CHIP_NO_ERROR;
170 : }
171 :
172 : /**
173 : * @brief Find a 4 uppercase hex digit hex value after a prefix string. Used to implement
174 : * fallback CN VID/PID encoding for PAA/PAI/DAC.
175 : *
176 : * @param[in] buffer - buffer in which to find the substring.
177 : * @param[in] prefix - prefix to match, which must be followed by 4 uppercase hex characters
178 : * @param[out] out_hex_value - on CHIP_NO_ERROR return, this will be the 16-bit hex value decoded.
179 : * @return CHIP_NO_ERROR on success, CHIP_ERROR_NOT_FOUND if not detected and
180 : * CHIP_ERROR_WRONG_CERT_DN if we saw the prefix but no valid hex string.
181 : */
182 679 : CHIP_ERROR Find16BitUpperCaseHexAfterPrefix(const ByteSpan & buffer, const char * prefix, uint16_t & out_hex_value)
183 : {
184 679 : chip::CharSpan prefix_span = chip::CharSpan::fromCharString(prefix);
185 :
186 679 : bool found_prefix_at_least_once = false;
187 :
188 : // Scan string from left to right, to find the desired full matching substring.
189 : //
190 : // IMPORTANT NOTE: We are trying to find the equivalent of prefix + [0-9A-F]{4}.
191 : // The appearance of the full prefix, but not followed by the hex value, must
192 : // be detected, as it is illegal if there isn't a valid prefix within the string.
193 : // This is why we first check for the prefix and then maybe check for the hex
194 : // value, rather than doing a single check of making sure there is enough space
195 : // for both.
196 9852 : for (size_t start_idx = 0; start_idx < buffer.size(); start_idx++)
197 : {
198 9852 : const uint8_t * cursor = buffer.data() + start_idx;
199 9852 : size_t remaining = buffer.size() - start_idx;
200 :
201 9852 : if (remaining < prefix_span.size())
202 : {
203 : // We can't possibly match prefix if not enough bytes left.
204 607 : break;
205 : }
206 :
207 : // Try to match the prefix at current position.
208 9248 : if (memcmp(cursor, prefix_span.data(), prefix_span.size()) != 0)
209 : {
210 : // Did not find prefix, move to next position.
211 9154 : continue;
212 : }
213 :
214 : // Otherwise, found prefix, skip to possible hex value.
215 94 : found_prefix_at_least_once = true;
216 94 : cursor += prefix_span.size();
217 94 : remaining -= prefix_span.size();
218 :
219 94 : constexpr size_t expected_hex_len = HEX_ENCODED_LENGTH(sizeof(uint16_t));
220 94 : if (remaining < expected_hex_len)
221 : {
222 : // We can't possibly match the hex values if not enough bytes left.
223 3 : break;
224 : }
225 :
226 : char hex_buf[expected_hex_len];
227 91 : memcpy(&hex_buf[0], cursor, sizeof(hex_buf));
228 :
229 91 : if (Encoding::UppercaseHexToUint16(&hex_buf[0], sizeof(hex_buf), out_hex_value) != 0)
230 : {
231 : // Found first full valid match, return success, out_hex_value already updated.
232 72 : return CHIP_NO_ERROR;
233 : }
234 :
235 : // Otherwise, did not find what we were looking for, try next position until exhausted.
236 : }
237 :
238 607 : return found_prefix_at_least_once ? CHIP_ERROR_WRONG_CERT_DN : CHIP_ERROR_NOT_FOUND;
239 : }
240 :
241 : } // namespace
242 :
243 : using HKDF_sha_crypto = HKDF_sha;
244 :
245 328 : CHIP_ERROR Spake2p::InternalHash(const uint8_t * in, size_t in_len)
246 : {
247 328 : const uint64_t u64_len = in_len;
248 :
249 : uint8_t lb[8];
250 328 : lb[0] = static_cast<uint8_t>((u64_len >> 0) & 0xff);
251 328 : lb[1] = static_cast<uint8_t>((u64_len >> 8) & 0xff);
252 328 : lb[2] = static_cast<uint8_t>((u64_len >> 16) & 0xff);
253 328 : lb[3] = static_cast<uint8_t>((u64_len >> 24) & 0xff);
254 328 : lb[4] = static_cast<uint8_t>((u64_len >> 32) & 0xff);
255 328 : lb[5] = static_cast<uint8_t>((u64_len >> 40) & 0xff);
256 328 : lb[6] = static_cast<uint8_t>((u64_len >> 48) & 0xff);
257 328 : lb[7] = static_cast<uint8_t>((u64_len >> 56) & 0xff);
258 :
259 328 : ReturnErrorOnFailure(Hash(lb, sizeof(lb)));
260 328 : if (in != nullptr)
261 : {
262 179 : ReturnErrorOnFailure(Hash(in, in_len));
263 : }
264 :
265 328 : return CHIP_NO_ERROR;
266 : }
267 :
268 156 : Spake2p::Spake2p(size_t _fe_size, size_t _point_size, size_t _hash_size)
269 : {
270 156 : fe_size = _fe_size;
271 156 : point_size = _point_size;
272 156 : hash_size = _hash_size;
273 :
274 156 : Kca = &Kcab[0];
275 156 : Kcb = &Kcab[hash_size / 2];
276 156 : Ka = &Kae[0];
277 156 : Ke = &Kae[hash_size / 2];
278 :
279 156 : M = nullptr;
280 156 : N = nullptr;
281 156 : G = nullptr;
282 156 : X = nullptr;
283 156 : Y = nullptr;
284 156 : L = nullptr;
285 156 : Z = nullptr;
286 156 : V = nullptr;
287 156 : w0 = nullptr;
288 156 : w1 = nullptr;
289 156 : xy = nullptr;
290 :
291 156 : order = nullptr;
292 156 : tempbn = nullptr;
293 156 : }
294 :
295 148 : CHIP_ERROR Spake2p::Init(const uint8_t * context, size_t context_len)
296 : {
297 148 : if (state != CHIP_SPAKE2P_STATE::PREINIT)
298 : {
299 1 : Clear();
300 : }
301 :
302 148 : ReturnErrorOnFailure(InitImpl());
303 148 : ReturnErrorOnFailure(PointLoad(spake2p_M_p256, sizeof(spake2p_M_p256), M));
304 148 : ReturnErrorOnFailure(PointLoad(spake2p_N_p256, sizeof(spake2p_N_p256), N));
305 148 : ReturnErrorOnFailure(InternalHash(context, context_len));
306 :
307 148 : state = CHIP_SPAKE2P_STATE::INIT;
308 148 : return CHIP_NO_ERROR;
309 : }
310 :
311 20 : CHIP_ERROR Spake2p::WriteMN()
312 : {
313 20 : ReturnErrorOnFailure(InternalHash(spake2p_M_p256, sizeof(spake2p_M_p256)));
314 20 : ReturnErrorOnFailure(InternalHash(spake2p_N_p256, sizeof(spake2p_N_p256)));
315 :
316 20 : return CHIP_NO_ERROR;
317 : }
318 :
319 10 : CHIP_ERROR Spake2p::BeginVerifier(const uint8_t * my_identity, size_t my_identity_len, const uint8_t * peer_identity,
320 : size_t peer_identity_len, const uint8_t * w0in, size_t w0in_len, const uint8_t * Lin,
321 : size_t Lin_len)
322 : {
323 10 : VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::INIT, CHIP_ERROR_INTERNAL);
324 :
325 10 : ReturnErrorOnFailure(InternalHash(peer_identity, peer_identity_len));
326 10 : ReturnErrorOnFailure(InternalHash(my_identity, my_identity_len));
327 10 : ReturnErrorOnFailure(WriteMN());
328 10 : ReturnErrorOnFailure(FELoad(w0in, w0in_len, w0));
329 10 : ReturnErrorOnFailure(PointLoad(Lin, Lin_len, L));
330 :
331 10 : state = CHIP_SPAKE2P_STATE::STARTED;
332 10 : role = CHIP_SPAKE2P_ROLE::VERIFIER;
333 10 : return CHIP_NO_ERROR;
334 : }
335 :
336 10 : CHIP_ERROR Spake2p::BeginProver(const uint8_t * my_identity, size_t my_identity_len, const uint8_t * peer_identity,
337 : size_t peer_identity_len, const uint8_t * w0sin, size_t w0sin_len, const uint8_t * w1sin,
338 : size_t w1sin_len)
339 : {
340 10 : VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::INIT, CHIP_ERROR_INTERNAL);
341 :
342 10 : ReturnErrorOnFailure(InternalHash(my_identity, my_identity_len));
343 10 : ReturnErrorOnFailure(InternalHash(peer_identity, peer_identity_len));
344 10 : ReturnErrorOnFailure(WriteMN());
345 10 : ReturnErrorOnFailure(FELoad(w0sin, w0sin_len, w0));
346 10 : ReturnErrorOnFailure(FELoad(w1sin, w1sin_len, w1));
347 :
348 10 : state = CHIP_SPAKE2P_STATE::STARTED;
349 10 : role = CHIP_SPAKE2P_ROLE::PROVER;
350 10 : return CHIP_NO_ERROR;
351 : }
352 :
353 20 : CHIP_ERROR Spake2p::ComputeRoundOne(const uint8_t * pab, size_t pab_len, uint8_t * out, size_t * out_len)
354 : {
355 20 : CHIP_ERROR error = CHIP_ERROR_INTERNAL;
356 20 : void * MN = nullptr; // Choose M if a prover, N if a verifier
357 20 : void * XY = nullptr; // Choose X if a prover, Y if a verifier
358 :
359 20 : VerifyOrExit(state == CHIP_SPAKE2P_STATE::STARTED, error = CHIP_ERROR_INTERNAL);
360 20 : VerifyOrExit(*out_len >= point_size, error = CHIP_ERROR_INTERNAL);
361 :
362 20 : ReturnErrorOnFailure(FEGenerate(xy));
363 :
364 20 : if (role == CHIP_SPAKE2P_ROLE::PROVER)
365 : {
366 10 : MN = M;
367 10 : XY = X;
368 : }
369 10 : else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
370 : {
371 10 : MN = N;
372 10 : XY = Y;
373 : }
374 20 : VerifyOrExit(MN != nullptr, error = CHIP_ERROR_INTERNAL);
375 20 : VerifyOrExit(XY != nullptr, error = CHIP_ERROR_INTERNAL);
376 :
377 20 : SuccessOrExit(error = PointAddMul(XY, G, xy, MN, w0));
378 20 : SuccessOrExit(error = PointWrite(XY, out, *out_len));
379 :
380 20 : state = CHIP_SPAKE2P_STATE::R1;
381 20 : error = CHIP_NO_ERROR;
382 20 : exit:
383 20 : *out_len = point_size;
384 20 : return error;
385 : }
386 :
387 20 : CHIP_ERROR Spake2p::ComputeRoundTwo(const uint8_t * in, size_t in_len, uint8_t * out, size_t * out_len)
388 : {
389 20 : CHIP_ERROR error = CHIP_ERROR_INTERNAL;
390 20 : MutableByteSpan out_span{ out, *out_len };
391 : uint8_t point_buffer[kMAX_Point_Length];
392 20 : void * MN = nullptr; // Choose N if a prover, M if a verifier
393 20 : void * XY = nullptr; // Choose Y if a prover, X if a verifier
394 20 : uint8_t * Kcaorb = nullptr; // Choose Kca if a prover, Kcb if a verifier
395 :
396 20 : VerifyOrExit(*out_len >= hash_size, error = CHIP_ERROR_INTERNAL);
397 20 : VerifyOrExit(state == CHIP_SPAKE2P_STATE::R1, error = CHIP_ERROR_INTERNAL);
398 20 : VerifyOrExit(in_len == point_size, error = CHIP_ERROR_INTERNAL);
399 :
400 20 : if (role == CHIP_SPAKE2P_ROLE::PROVER)
401 : {
402 10 : SuccessOrExit(error = PointWrite(X, point_buffer, point_size));
403 10 : SuccessOrExit(error = InternalHash(point_buffer, point_size));
404 10 : SuccessOrExit(error = InternalHash(in, in_len));
405 :
406 10 : MN = N;
407 10 : XY = Y;
408 10 : Kcaorb = Kca;
409 : }
410 10 : else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
411 : {
412 10 : SuccessOrExit(error = InternalHash(in, in_len));
413 10 : SuccessOrExit(error = PointWrite(Y, point_buffer, point_size));
414 10 : SuccessOrExit(error = InternalHash(point_buffer, point_size));
415 :
416 10 : MN = M;
417 10 : XY = X;
418 10 : Kcaorb = Kcb;
419 : }
420 20 : VerifyOrExit(MN != nullptr, error = CHIP_ERROR_INTERNAL);
421 20 : VerifyOrExit(XY != nullptr, error = CHIP_ERROR_INTERNAL);
422 :
423 20 : SuccessOrExit(error = PointLoad(in, in_len, XY));
424 20 : SuccessOrExit(error = PointIsValid(XY));
425 20 : SuccessOrExit(error = FEMul(tempbn, xy, w0));
426 20 : SuccessOrExit(error = PointInvert(MN));
427 20 : SuccessOrExit(error = PointAddMul(Z, XY, xy, MN, tempbn));
428 20 : SuccessOrExit(error = PointCofactorMul(Z));
429 :
430 20 : if (role == CHIP_SPAKE2P_ROLE::PROVER)
431 : {
432 10 : SuccessOrExit(error = FEMul(tempbn, w1, w0));
433 10 : SuccessOrExit(error = PointAddMul(V, XY, w1, MN, tempbn));
434 : }
435 10 : else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
436 : {
437 10 : SuccessOrExit(error = PointMul(V, L, xy));
438 : }
439 :
440 20 : SuccessOrExit(error = PointCofactorMul(V));
441 20 : SuccessOrExit(error = PointWrite(Z, point_buffer, point_size));
442 20 : SuccessOrExit(error = InternalHash(point_buffer, point_size));
443 :
444 20 : SuccessOrExit(error = PointWrite(V, point_buffer, point_size));
445 20 : SuccessOrExit(error = InternalHash(point_buffer, point_size));
446 :
447 20 : SuccessOrExit(error = FEWrite(w0, point_buffer, fe_size));
448 20 : SuccessOrExit(error = InternalHash(point_buffer, fe_size));
449 :
450 20 : SuccessOrExit(error = GenerateKeys());
451 :
452 20 : SuccessOrExit(error = Mac(Kcaorb, hash_size / 2, in, in_len, out_span));
453 20 : VerifyOrExit(out_span.size() == hash_size, error = CHIP_ERROR_INTERNAL);
454 :
455 20 : state = CHIP_SPAKE2P_STATE::R2;
456 20 : error = CHIP_NO_ERROR;
457 20 : exit:
458 20 : *out_len = hash_size;
459 20 : return error;
460 : }
461 :
462 20 : CHIP_ERROR Spake2p::GenerateKeys()
463 : {
464 : static const uint8_t info_keyconfirm[16] = { 'C', 'o', 'n', 'f', 'i', 'r', 'm', 'a', 't', 'i', 'o', 'n', 'K', 'e', 'y', 's' };
465 :
466 20 : MutableByteSpan Kae_span{ &Kae[0], sizeof(Kae) };
467 :
468 20 : ReturnErrorOnFailure(HashFinalize(Kae_span));
469 20 : ReturnErrorOnFailure(KDF(Ka, hash_size / 2, nullptr, 0, info_keyconfirm, sizeof(info_keyconfirm), Kcab, hash_size));
470 :
471 20 : return CHIP_NO_ERROR;
472 : }
473 :
474 19 : CHIP_ERROR Spake2p::KeyConfirm(const uint8_t * in, size_t in_len)
475 : {
476 : uint8_t point_buffer[kP256_Point_Length];
477 19 : void * XY = nullptr; // Choose X if a prover, Y if a verifier
478 19 : uint8_t * Kcaorb = nullptr; // Choose Kcb if a prover, Kca if a verifier
479 :
480 19 : VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::R2, CHIP_ERROR_INTERNAL);
481 :
482 19 : if (role == CHIP_SPAKE2P_ROLE::PROVER)
483 : {
484 10 : XY = X;
485 10 : Kcaorb = Kcb;
486 : }
487 9 : else if (role == CHIP_SPAKE2P_ROLE::VERIFIER)
488 : {
489 9 : XY = Y;
490 9 : Kcaorb = Kca;
491 : }
492 19 : VerifyOrReturnError(XY != nullptr, CHIP_ERROR_INTERNAL);
493 19 : VerifyOrReturnError(Kcaorb != nullptr, CHIP_ERROR_INTERNAL);
494 :
495 19 : ReturnErrorOnFailure(PointWrite(XY, point_buffer, point_size));
496 :
497 19 : CHIP_ERROR err = MacVerify(Kcaorb, hash_size / 2, in, in_len, point_buffer, point_size);
498 19 : if (err == CHIP_ERROR_INTERNAL)
499 : {
500 1 : ChipLogError(SecureChannel, "Failed to verify peer's MAC. This can happen when setup code is incorrect.");
501 : }
502 19 : ReturnErrorOnFailure(err);
503 :
504 18 : state = CHIP_SPAKE2P_STATE::KC;
505 18 : return CHIP_NO_ERROR;
506 : }
507 :
508 18 : CHIP_ERROR Spake2p::GetKeys(SessionKeystore & keystore, HkdfKeyHandle & key)
509 : {
510 18 : VerifyOrReturnError(state == CHIP_SPAKE2P_STATE::KC, CHIP_ERROR_INTERNAL);
511 :
512 18 : return keystore.CreateKey(ByteSpan(Ke, hash_size / 2), key);
513 : }
514 :
515 148 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::InitImpl()
516 : {
517 148 : ReturnErrorOnFailure(sha256_hash_ctx.Begin());
518 148 : ReturnErrorOnFailure(InitInternal());
519 148 : return CHIP_NO_ERROR;
520 : }
521 :
522 507 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::Hash(const uint8_t * in, size_t in_len)
523 : {
524 507 : ReturnErrorOnFailure(sha256_hash_ctx.AddData(ByteSpan{ in, in_len }));
525 507 : return CHIP_NO_ERROR;
526 : }
527 :
528 20 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::HashFinalize(MutableByteSpan & out_span)
529 : {
530 20 : ReturnErrorOnFailure(sha256_hash_ctx.Finish(out_span));
531 20 : return CHIP_NO_ERROR;
532 : }
533 :
534 20 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::KDF(const uint8_t * ikm, const size_t ikm_len, const uint8_t * salt,
535 : const size_t salt_len, const uint8_t * info, const size_t info_len, uint8_t * out,
536 : size_t out_len)
537 : {
538 20 : HKDF_sha_crypto mHKDF;
539 :
540 20 : ReturnErrorOnFailure(mHKDF.HKDF_SHA256(ikm, ikm_len, salt, salt_len, info, info_len, out, out_len));
541 :
542 20 : return CHIP_NO_ERROR;
543 20 : }
544 :
545 3 : CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeW0(uint8_t * w0out, size_t * w0_len, const uint8_t * w0sin, size_t w0sin_len)
546 : {
547 3 : ReturnErrorOnFailure(FELoad(w0sin, w0sin_len, w0));
548 3 : ReturnErrorOnFailure(FEWrite(w0, w0out, *w0_len));
549 :
550 3 : return CHIP_NO_ERROR;
551 : }
552 :
553 2 : CHIP_ERROR Spake2pVerifier::Serialize(MutableByteSpan & outSerialized) const
554 : {
555 2 : VerifyOrReturnError(outSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT);
556 :
557 2 : memcpy(&outSerialized.data()[0], mW0, sizeof(mW0));
558 2 : memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL));
559 :
560 2 : outSerialized.reduce_size(kSpake2p_VerifierSerialized_Length);
561 :
562 2 : return CHIP_NO_ERROR;
563 : }
564 :
565 9 : CHIP_ERROR Spake2pVerifier::Deserialize(const ByteSpan & inSerialized)
566 : {
567 9 : VerifyOrReturnError(inSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT);
568 :
569 8 : memcpy(mW0, &inSerialized.data()[0], sizeof(mW0));
570 8 : memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL));
571 :
572 8 : return CHIP_NO_ERROR;
573 : }
574 :
575 3 : CHIP_ERROR Spake2pVerifier::Generate(uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t setupPin)
576 : {
577 3 : uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 };
578 3 : ReturnErrorOnFailure(ComputeWS(pbkdf2IterCount, salt, setupPin, serializedWS, sizeof(serializedWS)));
579 :
580 3 : CHIP_ERROR err = CHIP_NO_ERROR;
581 : size_t len;
582 :
583 : // Create local Spake2+ object for w0 and L computations.
584 3 : Spake2p_P256_SHA256_HKDF_HMAC spake2p;
585 3 : uint8_t context[kSHA256_Hash_Length] = { 0 };
586 3 : SuccessOrExit(err = spake2p.Init(context, sizeof(context)));
587 :
588 : // Compute w0
589 3 : len = sizeof(mW0);
590 3 : SuccessOrExit(err = spake2p.ComputeW0(mW0, &len, &serializedWS[0], kSpake2p_WS_Length));
591 3 : VerifyOrExit(len == sizeof(mW0), err = CHIP_ERROR_INTERNAL);
592 :
593 : // Compute L
594 3 : len = sizeof(mL);
595 3 : SuccessOrExit(err = spake2p.ComputeL(mL, &len, &serializedWS[kSpake2p_WS_Length], kSpake2p_WS_Length));
596 3 : VerifyOrExit(len == sizeof(mL), err = CHIP_ERROR_INTERNAL);
597 :
598 3 : exit:
599 3 : spake2p.Clear();
600 3 : return err;
601 3 : }
602 :
603 9 : CHIP_ERROR Spake2pVerifier::ComputeWS(uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t setupPin, uint8_t * ws,
604 : uint32_t ws_len)
605 : {
606 9 : PBKDF2_sha256 pbkdf2;
607 : uint8_t littleEndianSetupPINCode[sizeof(uint32_t)];
608 9 : Encoding::LittleEndian::Put32(littleEndianSetupPINCode, setupPin);
609 :
610 9 : VerifyOrReturnError(salt.size() >= kSpake2p_Min_PBKDF_Salt_Length && salt.size() <= kSpake2p_Max_PBKDF_Salt_Length,
611 : CHIP_ERROR_INVALID_ARGUMENT);
612 9 : VerifyOrReturnError(pbkdf2IterCount >= kSpake2p_Min_PBKDF_Iterations && pbkdf2IterCount <= kSpake2p_Max_PBKDF_Iterations,
613 : CHIP_ERROR_INVALID_ARGUMENT);
614 :
615 9 : return pbkdf2.pbkdf2_sha256(littleEndianSetupPINCode, sizeof(littleEndianSetupPINCode), salt.data(), salt.size(),
616 9 : pbkdf2IterCount, ws_len, ws);
617 9 : }
618 :
619 625 : CHIP_ERROR ReadDerLength(Reader & reader, size_t & length)
620 : {
621 625 : length = 0;
622 :
623 625 : uint8_t cur_byte = 0;
624 625 : ReturnErrorOnFailure(reader.Read8(&cur_byte).StatusCode());
625 :
626 624 : if ((cur_byte & (1u << 7)) == 0)
627 : {
628 : // 7 bit length, the rest of the byte is the length.
629 553 : length = cur_byte & 0x7Fu;
630 553 : return CHIP_NO_ERROR;
631 : }
632 :
633 71 : CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT;
634 :
635 : // Did not early return: > 7 bit length, the number of bytes of the length is provided next.
636 71 : uint8_t length_bytes = cur_byte & 0x7Fu;
637 71 : VerifyOrReturnError((length_bytes >= 1) && (length_bytes <= sizeof(size_t)), CHIP_ERROR_INVALID_ARGUMENT);
638 70 : VerifyOrReturnError(reader.HasAtLeast(length_bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
639 :
640 148 : for (uint8_t i = 0; i < length_bytes; i++)
641 : {
642 83 : uint8_t cur_length_byte = 0;
643 83 : err = reader.Read8(&cur_length_byte).StatusCode();
644 83 : if (err != CHIP_NO_ERROR)
645 0 : break;
646 :
647 : // Cannot have zero padding on multi-byte lengths in DER, so first
648 : // byte must always be > 0.
649 83 : if ((i == 0) && (cur_length_byte == 0))
650 : {
651 2 : return CHIP_ERROR_INVALID_ARGUMENT;
652 : }
653 :
654 81 : length <<= 8;
655 81 : length |= cur_length_byte;
656 : }
657 :
658 : // Single-byte long length cannot be < 128: DER always encodes on smallest size
659 : // possible, so length zero should have been a single byte short length.
660 65 : if ((length_bytes == 1) && (length < 128))
661 : {
662 1 : return CHIP_ERROR_INVALID_ARGUMENT;
663 : }
664 :
665 64 : return CHIP_NO_ERROR;
666 : }
667 :
668 261 : CHIP_ERROR ConvertIntegerRawToDerWithoutTag(const ByteSpan & raw_integer, MutableByteSpan & out_der_integer)
669 : {
670 261 : return ConvertIntegerRawToDerInternal(raw_integer, out_der_integer, /* include_tag_and_length = */ false);
671 : }
672 :
673 24 : CHIP_ERROR ConvertIntegerRawToDer(const ByteSpan & raw_integer, MutableByteSpan & out_der_integer)
674 : {
675 24 : return ConvertIntegerRawToDerInternal(raw_integer, out_der_integer, /* include_tag_and_length = */ true);
676 : }
677 :
678 5 : CHIP_ERROR EcdsaRawSignatureToAsn1(size_t fe_length_bytes, const ByteSpan & raw_sig, MutableByteSpan & out_asn1_sig)
679 : {
680 5 : VerifyOrReturnError(fe_length_bytes > 0, CHIP_ERROR_INVALID_ARGUMENT);
681 5 : VerifyOrReturnError(raw_sig.size() == (2u * fe_length_bytes), CHIP_ERROR_INVALID_ARGUMENT);
682 5 : VerifyOrReturnError(out_asn1_sig.size() >= (raw_sig.size() + kMax_ECDSA_X9Dot62_Asn1_Overhead), CHIP_ERROR_BUFFER_TOO_SMALL);
683 :
684 : // Write both R an S integers past the overhead, we will shift them back later if we only needed 2 size bytes.
685 5 : uint8_t * cursor = out_asn1_sig.data() + kMinSequenceOverhead;
686 5 : size_t remaining = out_asn1_sig.size() - kMinSequenceOverhead;
687 :
688 5 : size_t integers_length = 0;
689 :
690 : // Write R (first `fe_length_bytes` block of raw signature)
691 : {
692 5 : MutableByteSpan out_der_integer(cursor, remaining);
693 5 : ReturnErrorOnFailure(ConvertIntegerRawToDer(raw_sig.SubSpan(0, fe_length_bytes), out_der_integer));
694 5 : VerifyOrReturnError(out_der_integer.size() <= remaining, CHIP_ERROR_INTERNAL);
695 :
696 5 : integers_length += out_der_integer.size();
697 5 : remaining -= out_der_integer.size();
698 5 : cursor += out_der_integer.size();
699 : }
700 :
701 : // Write S (second `fe_length_bytes` block of raw signature)
702 : {
703 5 : MutableByteSpan out_der_integer(cursor, remaining);
704 5 : ReturnErrorOnFailure(ConvertIntegerRawToDer(raw_sig.SubSpan(fe_length_bytes, fe_length_bytes), out_der_integer));
705 5 : VerifyOrReturnError(out_der_integer.size() <= remaining, CHIP_ERROR_INTERNAL);
706 5 : integers_length += out_der_integer.size();
707 : }
708 :
709 : // We only support outputs that would use 1 or 2 bytes of DER length after the SEQUENCE tag
710 5 : VerifyOrReturnError(integers_length <= UINT8_MAX, CHIP_ERROR_INVALID_ARGUMENT);
711 :
712 : // We now know the length of both variable sized integers in the sequence, so we
713 : // can write the tag and length.
714 5 : BufferWriter writer(out_asn1_sig);
715 :
716 : // Put SEQUENCE tag
717 5 : writer.Put(kSeqTag);
718 :
719 : // Put the length over 1 or two bytes depending on case
720 5 : constexpr uint8_t kExtendedLengthMarker = 0x80u;
721 5 : if (integers_length > 127u)
722 : {
723 1 : writer.Put(static_cast<uint8_t>(kExtendedLengthMarker | 1)); // Length is extended length, over 1 subsequent byte
724 1 : writer.Put(static_cast<uint8_t>(integers_length));
725 : }
726 : else
727 : {
728 : // Length is directly in the first byte with MSB clear if <= 127.
729 4 : writer.Put(static_cast<uint8_t>(integers_length));
730 : }
731 :
732 : // Put the contents of the integers previously serialized in the buffer.
733 : // The writer.Put is memmove-safe, so the shifting will happen from the read
734 : // of the same buffer where the write is taking place.
735 5 : writer.Put(out_asn1_sig.data() + kMinSequenceOverhead, integers_length);
736 :
737 5 : size_t actually_written = 0;
738 5 : VerifyOrReturnError(writer.Fit(actually_written), CHIP_ERROR_BUFFER_TOO_SMALL);
739 :
740 5 : out_asn1_sig = out_asn1_sig.SubSpan(0, actually_written);
741 5 : return CHIP_NO_ERROR;
742 : }
743 :
744 184 : CHIP_ERROR EcdsaAsn1SignatureToRaw(size_t fe_length_bytes, const ByteSpan & asn1_sig, MutableByteSpan & out_raw_sig)
745 : {
746 184 : VerifyOrReturnError(fe_length_bytes > 0, CHIP_ERROR_INVALID_ARGUMENT);
747 184 : VerifyOrReturnError(asn1_sig.size() > kMinSequenceOverhead, CHIP_ERROR_BUFFER_TOO_SMALL);
748 :
749 : // Output raw signature is <r,s> both of which are of fe_length_bytes (see SEC1).
750 184 : VerifyOrReturnError(out_raw_sig.size() >= (2u * fe_length_bytes), CHIP_ERROR_BUFFER_TOO_SMALL);
751 :
752 184 : Reader reader(asn1_sig);
753 :
754 : // Make sure we have a starting Sequence
755 184 : uint8_t tag = 0;
756 184 : ReturnErrorOnFailure(reader.Read8(&tag).StatusCode());
757 184 : VerifyOrReturnError(tag == kSeqTag, CHIP_ERROR_INVALID_ARGUMENT);
758 :
759 : // Read length of sequence
760 184 : size_t tag_len = 0;
761 184 : ReturnErrorOnFailure(ReadDerLength(reader, tag_len));
762 :
763 : // Length of sequence must match what is left of signature
764 184 : VerifyOrReturnError(tag_len == reader.Remaining(), CHIP_ERROR_INVALID_ARGUMENT);
765 :
766 : // Can now clear raw signature integers r,s one by one
767 184 : uint8_t * raw_cursor = out_raw_sig.data();
768 :
769 : // Read R
770 184 : ReturnErrorOnFailure(ReadDerUnsignedIntegerIntoRaw(reader, MutableByteSpan{ raw_cursor, fe_length_bytes }));
771 :
772 184 : raw_cursor += fe_length_bytes;
773 :
774 : // Read S
775 184 : ReturnErrorOnFailure(ReadDerUnsignedIntegerIntoRaw(reader, MutableByteSpan{ raw_cursor, fe_length_bytes }));
776 :
777 184 : out_raw_sig = out_raw_sig.SubSpan(0, (2u * fe_length_bytes));
778 :
779 184 : return CHIP_NO_ERROR;
780 : }
781 :
782 10 : CHIP_ERROR AES_CTR_crypt(const uint8_t * input, size_t input_length, const Aes128KeyHandle & key, const uint8_t * nonce,
783 : size_t nonce_length, uint8_t * output)
784 : {
785 : // Discard tag portion of CCM to apply only CTR mode encryption/decryption.
786 10 : constexpr size_t kTagLen = Crypto::kAES_CCM128_Tag_Length;
787 : uint8_t tag[kTagLen];
788 :
789 10 : return AES_CCM_encrypt(input, input_length, nullptr, 0, key, nonce, nonce_length, output, tag, kTagLen);
790 : }
791 :
792 814 : CHIP_ERROR GenerateCompressedFabricId(const Crypto::P256PublicKey & root_public_key, uint64_t fabric_id,
793 : MutableByteSpan & out_compressed_fabric_id)
794 : {
795 814 : VerifyOrReturnError(root_public_key.IsUncompressed(), CHIP_ERROR_INVALID_ARGUMENT);
796 813 : VerifyOrReturnError(out_compressed_fabric_id.size() >= kCompressedFabricIdentifierSize, CHIP_ERROR_BUFFER_TOO_SMALL);
797 :
798 : // Ensure proper endianness for Fabric ID (i.e. big-endian as it appears in certificates)
799 : uint8_t fabric_id_as_big_endian_salt[kCompressedFabricIdentifierSize];
800 812 : chip::Encoding::BigEndian::Put64(&fabric_id_as_big_endian_salt[0], fabric_id);
801 :
802 : // Compute Compressed fabric reference per spec pseudocode
803 : // CompressedFabricIdentifier =
804 : // CHIP_Crypto_KDF(
805 : // inputKey := TargetOperationalRootPublicKey,
806 : // salt:= TargetOperationalFabricID,
807 : // info := CompressedFabricInfo,
808 : // len := 64)
809 : //
810 : // NOTE: len=64 bits is implied by output buffer size when calling HKDF_sha::HKDF_SHA256.
811 :
812 812 : constexpr uint8_t kCompressedFabricInfo[16] = /* "CompressedFabric" */
813 : { 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63 };
814 812 : HKDF_sha hkdf;
815 :
816 : // Must drop uncompressed point form format specifier (first byte), per spec method
817 812 : ByteSpan input_key_span(root_public_key.ConstBytes() + 1, root_public_key.Length() - 1);
818 :
819 812 : CHIP_ERROR status = hkdf.HKDF_SHA256(
820 : input_key_span.data(), input_key_span.size(), &fabric_id_as_big_endian_salt[0], sizeof(fabric_id_as_big_endian_salt),
821 : &kCompressedFabricInfo[0], sizeof(kCompressedFabricInfo), out_compressed_fabric_id.data(), kCompressedFabricIdentifierSize);
822 :
823 : // Resize output to final bounds on success
824 812 : if (status == CHIP_NO_ERROR)
825 : {
826 812 : out_compressed_fabric_id = out_compressed_fabric_id.SubSpan(0, kCompressedFabricIdentifierSize);
827 : }
828 :
829 812 : return status;
830 812 : }
831 :
832 11 : CHIP_ERROR GenerateCompressedFabricId(const Crypto::P256PublicKey & rootPublicKey, uint64_t fabricId, uint64_t & compressedFabricId)
833 : {
834 : uint8_t allocated[sizeof(fabricId)];
835 11 : MutableByteSpan span(allocated);
836 11 : ReturnErrorOnFailure(GenerateCompressedFabricId(rootPublicKey, fabricId, span));
837 : // Decode compressed fabric ID accounting for endianness, as GenerateCompressedFabricId()
838 : // returns a binary buffer and is agnostic of usage of the output as an integer type.
839 11 : compressedFabricId = Encoding::BigEndian::Get64(allocated);
840 11 : return CHIP_NO_ERROR;
841 : }
842 :
843 : /* Operational Group Key Group, Security Info: "GroupKey v1.0" */
844 : static const uint8_t kGroupSecurityInfo[] = { 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x20, 0x76, 0x31, 0x2e, 0x30 };
845 :
846 : /* Group Key Derivation Function, Info: "GroupKeyHash" ” */
847 : static const uint8_t kGroupKeyHashInfo[] = { 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x48, 0x61, 0x73, 0x68 };
848 : static const uint8_t kGroupKeyHashSalt[0] = {};
849 :
850 : /*
851 : OperationalGroupKey =
852 : Crypto_KDF
853 : (
854 : InputKey = Epoch Key,
855 : Salt = CompressedFabricIdentifier,
856 : Info = "GroupKey v1.0",
857 : Length = CRYPTO_SYMMETRIC_KEY_LENGTH_BITS
858 : )
859 : */
860 200 : CHIP_ERROR DeriveGroupOperationalKey(const ByteSpan & epoch_key, const ByteSpan & compressed_fabric_id, MutableByteSpan & out_key)
861 : {
862 200 : VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == epoch_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
863 199 : VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES <= out_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
864 :
865 199 : Crypto::HKDF_sha crypto;
866 199 : return crypto.HKDF_SHA256(epoch_key.data(), epoch_key.size(), compressed_fabric_id.data(), compressed_fabric_id.size(),
867 : kGroupSecurityInfo, sizeof(kGroupSecurityInfo), out_key.data(),
868 199 : Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
869 199 : }
870 :
871 : /*
872 : GKH = Crypto_KDF (
873 : InputKey = OperationalGroupKey,
874 : Salt = [],
875 : Info = "GroupKeyHash",
876 : Length = 16)
877 : */
878 199 : CHIP_ERROR DeriveGroupSessionId(const ByteSpan & operational_key, uint16_t & session_id)
879 : {
880 199 : VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == operational_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
881 198 : Crypto::HKDF_sha crypto;
882 : uint8_t out_key[sizeof(uint16_t)];
883 :
884 198 : ReturnErrorOnFailure(crypto.HKDF_SHA256(operational_key.data(), operational_key.size(), kGroupKeyHashSalt,
885 : sizeof(kGroupKeyHashSalt), kGroupKeyHashInfo, sizeof(kGroupKeyHashInfo), out_key,
886 : sizeof(out_key)));
887 198 : session_id = Encoding::BigEndian::Get16(out_key);
888 198 : return CHIP_NO_ERROR;
889 198 : }
890 :
891 : /* Operational Group Key Group, PrivacyKey Info: "PrivacyKey" */
892 : static const uint8_t kGroupPrivacyInfo[] = { 'P', 'r', 'i', 'v', 'a', 'c', 'y', 'K', 'e', 'y' };
893 :
894 : /*
895 : PrivacyKey =
896 : Crypto_KDF
897 : (
898 : InputKey = EncryptionKey,
899 : Salt = [],
900 : Info = "PrivacyKey",
901 : Length = CRYPTO_SYMMETRIC_KEY_LENGTH_BITS
902 : )
903 : */
904 1085 : CHIP_ERROR DeriveGroupPrivacyKey(const ByteSpan & encryption_key, MutableByteSpan & out_key)
905 : {
906 1085 : VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == encryption_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
907 1084 : VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES <= out_key.size(), CHIP_ERROR_INVALID_ARGUMENT);
908 :
909 1084 : constexpr ByteSpan null_span = ByteSpan();
910 :
911 1084 : Crypto::HKDF_sha crypto;
912 1084 : return crypto.HKDF_SHA256(encryption_key.data(), encryption_key.size(), null_span.data(), null_span.size(), kGroupPrivacyInfo,
913 1084 : sizeof(kGroupPrivacyInfo), out_key.data(), Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
914 1084 : }
915 :
916 196 : CHIP_ERROR DeriveGroupOperationalCredentials(const ByteSpan & epoch_key, const ByteSpan & compressed_fabric_id,
917 : GroupOperationalCredentials & operational_credentials)
918 : {
919 196 : MutableByteSpan encryption_key(operational_credentials.encryption_key);
920 196 : MutableByteSpan privacy_key(operational_credentials.privacy_key);
921 :
922 196 : ReturnErrorOnFailure(Crypto::DeriveGroupOperationalKey(epoch_key, compressed_fabric_id, encryption_key));
923 196 : ReturnErrorOnFailure(Crypto::DeriveGroupSessionId(encryption_key, operational_credentials.hash));
924 196 : ReturnErrorOnFailure(Crypto::DeriveGroupPrivacyKey(encryption_key, privacy_key));
925 :
926 196 : return CHIP_NO_ERROR;
927 : }
928 :
929 8 : CHIP_ERROR GenerateVendorFabricBindingMessage(FabricBindingVersion fabricBindingVersion, const P256PublicKey & rootPublicKey,
930 : FabricId fabricId, uint16_t vendorId, MutableByteSpan & outputSpan)
931 : {
932 : // Only V1 supported yet.
933 8 : switch (fabricBindingVersion)
934 : {
935 7 : case FabricBindingVersion::kVersion1:
936 7 : break;
937 1 : default:
938 1 : return CHIP_ERROR_INVALID_ARGUMENT;
939 : }
940 :
941 7 : Encoding::BigEndian::BufferWriter writer(outputSpan);
942 :
943 : // vendor_fabric_binding_message := fabric_binding_version (1 byte) || root_public_key || fabric_id || vendor_id
944 7 : writer.Put8(to_underlying(fabricBindingVersion))
945 7 : .Put(rootPublicKey.ConstBytes(), rootPublicKey.Length())
946 7 : .Put64(fabricId)
947 7 : .Put16(vendorId);
948 :
949 7 : size_t actuallyWritten = 0;
950 7 : VerifyOrReturnError(writer.Fit(actuallyWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
951 :
952 6 : outputSpan.reduce_size(actuallyWritten);
953 6 : return CHIP_NO_ERROR;
954 : }
955 :
956 13 : CHIP_ERROR GenerateVendorIdVerificationToBeSigned(FabricIndex fabricIndex, const ByteSpan & clientChallenge,
957 : const ByteSpan & attestationChallenge,
958 : const ByteSpan & vendorFabricBindingMessage,
959 : const ByteSpan & vidVerificationStatement, MutableByteSpan & outputSpan)
960 : {
961 13 : VerifyOrReturnError((clientChallenge.size() == kVendorIdVerificationClientChallengeSize) &&
962 : (attestationChallenge.size() == CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES) &&
963 : !vendorFabricBindingMessage.empty(),
964 : CHIP_ERROR_INVALID_ARGUMENT);
965 :
966 : // Extract binding version from vendorFabricBindingMessage. Only V1 supported yet.
967 6 : uint8_t fabricBindingVersion = vendorFabricBindingMessage[0];
968 6 : VerifyOrReturnError(fabricBindingVersion == to_underlying(FabricBindingVersion::kVersion1), CHIP_ERROR_INVALID_ARGUMENT);
969 :
970 5 : Encoding::BigEndian::BufferWriter writer(outputSpan);
971 :
972 : // vendor_id_verification_tbs := fabric_binding_version || client_challenge || attestation_challenge || fabric_index ||
973 : // vendor_fabric_binding_message || <vid_verification_statement>
974 5 : writer.Put8(fabricBindingVersion)
975 5 : .Put(clientChallenge.data(), clientChallenge.size())
976 5 : .Put(attestationChallenge.data(), attestationChallenge.size())
977 5 : .Put8(fabricIndex)
978 5 : .Put(vendorFabricBindingMessage.data(), vendorFabricBindingMessage.size())
979 5 : .Put(vidVerificationStatement.data(), vidVerificationStatement.size());
980 :
981 5 : size_t actuallyWritten = 0;
982 5 : VerifyOrReturnError(writer.Fit(actuallyWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
983 :
984 4 : outputSpan.reduce_size(actuallyWritten);
985 4 : return CHIP_NO_ERROR;
986 : }
987 :
988 825 : CHIP_ERROR ExtractVIDPIDFromAttributeString(DNAttrType attrType, const ByteSpan & attr,
989 : AttestationCertVidPid & vidpidFromMatterAttr, AttestationCertVidPid & vidpidFromCNAttr)
990 : {
991 825 : VerifyOrReturnError(attrType != DNAttrType::kUnspecified, CHIP_NO_ERROR);
992 824 : VerifyOrReturnError(!attr.empty(), CHIP_ERROR_INVALID_ARGUMENT);
993 :
994 823 : if (attrType == DNAttrType::kMatterVID || attrType == DNAttrType::kMatterPID)
995 : {
996 : uint16_t matterAttr;
997 482 : VerifyOrReturnError(attr.size() == kVIDandPIDHexLength, CHIP_ERROR_WRONG_CERT_DN);
998 472 : VerifyOrReturnError(Encoding::UppercaseHexToUint16(reinterpret_cast<const char *>(attr.data()), attr.size(), matterAttr) ==
999 : sizeof(matterAttr),
1000 : CHIP_ERROR_WRONG_CERT_DN);
1001 :
1002 468 : if (attrType == DNAttrType::kMatterVID)
1003 : {
1004 : // Not more than one VID attribute can be present.
1005 291 : VerifyOrReturnError(!vidpidFromMatterAttr.mVendorId.HasValue(), CHIP_ERROR_WRONG_CERT_DN);
1006 291 : vidpidFromMatterAttr.mVendorId.SetValue(static_cast<VendorId>(matterAttr));
1007 : }
1008 : else
1009 : {
1010 : // Not more than one PID attribute can be present.
1011 177 : VerifyOrReturnError(!vidpidFromMatterAttr.mProductId.HasValue(), CHIP_ERROR_WRONG_CERT_DN);
1012 177 : vidpidFromMatterAttr.mProductId.SetValue(matterAttr);
1013 : }
1014 468 : }
1015 : // Otherwise, it is a CommonName attribute.
1016 345 : else if (!vidpidFromCNAttr.Initialized())
1017 : {
1018 345 : ByteSpan attr_source_span{ attr };
1019 345 : if (attr_source_span.size() > chip::Crypto::kMax_CommonNameAttr_Length)
1020 : {
1021 0 : attr_source_span.reduce_size(chip::Crypto::kMax_CommonNameAttr_Length);
1022 : }
1023 :
1024 : // Try to find a valid Vendor ID encoded in fallback method.
1025 345 : uint16_t vid = 0;
1026 345 : CHIP_ERROR err = Find16BitUpperCaseHexAfterPrefix(attr_source_span, kVIDPrefixForCNEncoding, vid);
1027 345 : if (err == CHIP_NO_ERROR)
1028 : {
1029 41 : vidpidFromCNAttr.mVendorId.SetValue(static_cast<VendorId>(vid));
1030 : }
1031 304 : else if (err != CHIP_ERROR_NOT_FOUND)
1032 : {
1033 : // This indicates a bad/ambiguous format.
1034 20 : return err;
1035 : }
1036 :
1037 : // Try to find a valid Product ID encoded in fallback method.
1038 334 : uint16_t pid = 0;
1039 334 : err = Find16BitUpperCaseHexAfterPrefix(attr_source_span, kPIDPrefixForCNEncoding, pid);
1040 334 : if (err == CHIP_NO_ERROR)
1041 : {
1042 31 : vidpidFromCNAttr.mProductId.SetValue(pid);
1043 : }
1044 303 : else if (err != CHIP_ERROR_NOT_FOUND)
1045 : {
1046 : // This indicates a bad/ambiguous format.
1047 9 : return err;
1048 : }
1049 : }
1050 :
1051 793 : return CHIP_NO_ERROR;
1052 : }
1053 :
1054 : // Generates the to-be-signed portion of a PKCS#10 CSR (`CertificationRequestInformation`)
1055 : // that contains the
1056 2 : static CHIP_ERROR GenerateCertificationRequestInformation(ASN1Writer & writer, const Crypto::P256PublicKey & pubkey)
1057 : {
1058 2 : CHIP_ERROR err = CHIP_NO_ERROR;
1059 : /**
1060 : *
1061 : * CertificationRequestInfo ::=
1062 : * SEQUENCE {
1063 : * version INTEGER { v1(0) } (v1,...),
1064 : * subject Name,
1065 : * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
1066 : * attributes [0] Attributes{{ CRIAttributes }}
1067 : * }
1068 : */
1069 2 : ASN1_START_SEQUENCE
1070 : {
1071 2 : ASN1_ENCODE_INTEGER(0); // version INTEGER { v1(0) }
1072 :
1073 : // subject Name
1074 2 : ASN1_START_SEQUENCE
1075 : {
1076 2 : ASN1_START_SET
1077 : {
1078 2 : ASN1_START_SEQUENCE
1079 : {
1080 : // Any subject, placeholder is good, since this
1081 : // is going to usually be ignored
1082 2 : ASN1_ENCODE_OBJECT_ID(kOID_AttributeType_OrganizationalUnitName);
1083 2 : ASN1_ENCODE_STRING(kASN1UniversalTag_UTF8String, "CSA", static_cast<uint16_t>(strlen("CSA")));
1084 : }
1085 2 : ASN1_END_SEQUENCE;
1086 : }
1087 2 : ASN1_END_SET;
1088 : }
1089 2 : ASN1_END_SEQUENCE;
1090 :
1091 : // subjectPKInfo
1092 2 : ASN1_START_SEQUENCE
1093 : {
1094 2 : ASN1_START_SEQUENCE
1095 : {
1096 2 : ASN1_ENCODE_OBJECT_ID(kOID_PubKeyAlgo_ECPublicKey);
1097 2 : ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1);
1098 : }
1099 2 : ASN1_END_SEQUENCE;
1100 2 : ReturnErrorOnFailure(writer.PutBitString(0, pubkey, static_cast<uint8_t>(pubkey.Length())));
1101 : }
1102 2 : ASN1_END_SEQUENCE;
1103 :
1104 : // attributes [0]
1105 2 : ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0)
1106 : {
1107 : // Using a plain empty attributes request
1108 2 : ASN1_START_SEQUENCE
1109 : {
1110 2 : ASN1_ENCODE_OBJECT_ID(kOID_Extension_CSRRequest);
1111 2 : ASN1_START_SET
1112 : {
1113 2 : ASN1_START_SEQUENCE {}
1114 2 : ASN1_END_SEQUENCE;
1115 : }
1116 2 : ASN1_END_SET;
1117 : }
1118 2 : ASN1_END_SEQUENCE;
1119 : }
1120 2 : ASN1_END_CONSTRUCTED;
1121 : }
1122 2 : ASN1_END_SEQUENCE;
1123 2 : exit:
1124 2 : return err;
1125 : }
1126 :
1127 3 : CHIP_ERROR GenerateCertificateSigningRequest(const P256Keypair * keypair, MutableByteSpan & csr_span)
1128 : {
1129 3 : VerifyOrReturnError(keypair != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
1130 2 : VerifyOrReturnError(csr_span.size() >= kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL);
1131 :
1132 : // First pass: Generate the CertificatioRequestInformation inner
1133 : // encoding one time, to sign it, before re-generating it within the
1134 : // full ASN1 writer later, since it's easier than trying to
1135 : // figure-out the span we need to sign of the overall object.
1136 1 : P256ECDSASignature signature;
1137 :
1138 : {
1139 : // The first pass will just generate a signature, so we can use the
1140 : // output buffer as scratch to avoid needing more stack space. There
1141 : // are no secrets here and the contents is not reused since all we
1142 : // need is the signature which is already separately stored.
1143 : ASN1Writer toBeSignedWriter;
1144 1 : toBeSignedWriter.Init(csr_span);
1145 1 : CHIP_ERROR err = GenerateCertificationRequestInformation(toBeSignedWriter, keypair->Pubkey());
1146 1 : ReturnErrorOnFailure(err);
1147 :
1148 1 : size_t encodedLen = (uint16_t) toBeSignedWriter.GetLengthWritten();
1149 : // This should not/will not happen
1150 1 : if (encodedLen > csr_span.size())
1151 : {
1152 0 : return CHIP_ERROR_INTERNAL;
1153 : }
1154 :
1155 1 : err = keypair->ECDSA_sign_msg(csr_span.data(), encodedLen, signature);
1156 1 : ReturnErrorOnFailure(err);
1157 : }
1158 :
1159 : // Second pass: Generate the entire CSR body, restarting a new write
1160 : // of the CertificationRequestInformation (cheap) and adding the
1161 : // signature.
1162 : //
1163 : // See RFC2986 for ASN.1 module, repeated here in snippets
1164 1 : CHIP_ERROR err = CHIP_NO_ERROR;
1165 :
1166 : ASN1Writer writer;
1167 1 : writer.Init(csr_span);
1168 :
1169 1 : ASN1_START_SEQUENCE
1170 : {
1171 :
1172 : /* CertificationRequestInfo ::=
1173 : * SEQUENCE {
1174 : * version INTEGER { v1(0) } (v1,...),
1175 : * subject Name,
1176 : * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
1177 : * attributes [0] Attributes{{ CRIAttributes }}
1178 : * }
1179 : */
1180 1 : GenerateCertificationRequestInformation(writer, keypair->Pubkey());
1181 :
1182 : // algorithm AlgorithmIdentifier
1183 1 : ASN1_START_SEQUENCE
1184 : {
1185 : // See RFC5480 sec 2.1
1186 1 : ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256);
1187 : }
1188 1 : ASN1_END_SEQUENCE;
1189 :
1190 : // signature BIT STRING --> ECDSA-with-SHA256 signature with P256 key with R,S integers format
1191 : // (see RFC3279 sec 2.2.3 ECDSA Signature Algorithm)
1192 1 : ASN1_START_BIT_STRING_ENCAPSULATED
1193 : {
1194 : // Convert raw signature to embedded signature
1195 1 : FixedByteSpan<Crypto::kP256_ECDSA_Signature_Length_Raw> rawSig(signature.Bytes());
1196 :
1197 : uint8_t derInt[kP256_FE_Length + kEmitDerIntegerWithoutTagOverhead];
1198 :
1199 : // Ecdsa-Sig-Value ::= SEQUENCE
1200 1 : ASN1_START_SEQUENCE
1201 : {
1202 : using P256IntegerSpan = FixedByteSpan<Crypto::kP256_FE_Length>;
1203 : // r INTEGER
1204 : {
1205 1 : MutableByteSpan derIntSpan(derInt, sizeof(derInt));
1206 1 : ReturnErrorOnFailure(ConvertIntegerRawToDerWithoutTag(P256IntegerSpan(rawSig.data()), derIntSpan));
1207 1 : ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false,
1208 : derIntSpan.data(), static_cast<uint16_t>(derIntSpan.size())));
1209 : }
1210 :
1211 : // s INTEGER
1212 : {
1213 1 : MutableByteSpan derIntSpan(derInt, sizeof(derInt));
1214 1 : ReturnErrorOnFailure(
1215 : ConvertIntegerRawToDerWithoutTag(P256IntegerSpan(rawSig.data() + kP256_FE_Length), derIntSpan));
1216 1 : ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false,
1217 : derIntSpan.data(), static_cast<uint16_t>(derIntSpan.size())));
1218 : }
1219 : }
1220 1 : ASN1_END_SEQUENCE;
1221 : }
1222 1 : ASN1_END_ENCAPSULATED;
1223 : }
1224 1 : ASN1_END_SEQUENCE;
1225 :
1226 1 : exit:
1227 : // Update size of output buffer on success
1228 1 : if (err == CHIP_NO_ERROR)
1229 : {
1230 1 : csr_span.reduce_size(writer.GetLengthWritten());
1231 : }
1232 1 : return err;
1233 1 : }
1234 :
1235 60 : CHIP_ERROR VerifyCertificateSigningRequestFormat(const uint8_t * csr, size_t csr_length)
1236 : {
1237 : // Ensure we have enough size to validate header, and that our assumptions are met
1238 : // for some tag computations below. A csr_length > 65535 would never be seen in
1239 : // practice.
1240 60 : VerifyOrReturnError((csr_length >= 16) && (csr_length <= 65535), CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
1241 :
1242 58 : Reader reader(csr, csr_length);
1243 :
1244 : // Ensure we have an outermost SEQUENCE
1245 58 : uint8_t seq_header = 0;
1246 58 : ReturnErrorOnFailure(reader.Read8(&seq_header).StatusCode());
1247 58 : VerifyOrReturnError(seq_header == kSeqTag, CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
1248 :
1249 56 : size_t seq_length = 0;
1250 56 : VerifyOrReturnError(ReadDerLength(reader, seq_length) == CHIP_NO_ERROR, CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
1251 : // Ensure that outer length matches sequence length + tag overhead, otherwise
1252 : // we have trailing garbage
1253 56 : size_t header_overhead = (seq_length <= 127) ? 2 : ((seq_length <= 255) ? 3 : 4);
1254 56 : VerifyOrReturnError(csr_length == (seq_length + header_overhead), CHIP_ERROR_UNSUPPORTED_CERT_FORMAT);
1255 :
1256 52 : return CHIP_NO_ERROR;
1257 : }
1258 :
1259 78 : const char * PemEncoder::NextLine()
1260 : {
1261 78 : bool hasLine = false;
1262 :
1263 78 : switch (mState)
1264 : {
1265 8 : case State::kPrintHeader: {
1266 : // The `.48s` is to make sure the header is not wider than out internal string buffer. We clamp the header.
1267 8 : mStringBuilder.Reset().AddFormat("-----BEGIN %.48s-----", mEncodedElement);
1268 8 : mState = mDerBytes.empty() ? State::kPrintFooter : State::kPrintBody;
1269 8 : hasLine = true;
1270 8 : break;
1271 : }
1272 52 : case State::kPrintBody: {
1273 52 : size_t remaining = mDerBytes.size() - mProcessedBytes;
1274 52 : size_t chunkSizeBytes = std::min(remaining, kNumBytesPerLine);
1275 :
1276 : {
1277 : char base64EncodedBuf[kLineBufferSize];
1278 : size_t encodedLen = static_cast<size_t>(
1279 52 : Base64Encode(mDerBytes.data() + mProcessedBytes, static_cast<uint16_t>(chunkSizeBytes), base64EncodedBuf));
1280 52 : VerifyOrDie(encodedLen < sizeof(base64EncodedBuf));
1281 52 : base64EncodedBuf[encodedLen] = '\0';
1282 52 : mStringBuilder.Reset().Add(base64EncodedBuf);
1283 : }
1284 :
1285 52 : mProcessedBytes += chunkSizeBytes;
1286 52 : mState = (mProcessedBytes < mDerBytes.size()) ? State::kPrintBody : State::kPrintFooter;
1287 52 : hasLine = true;
1288 52 : break;
1289 : }
1290 8 : case State::kPrintFooter: {
1291 : // The `.50s` is to make sure the header is not wider than out internal string buffer. We clamp the footer.
1292 8 : mStringBuilder.Reset().AddFormat("-----END %.50s-----", mEncodedElement);
1293 8 : mState = State::kDone;
1294 8 : hasLine = true;
1295 8 : break;
1296 : }
1297 10 : case State::kDone:
1298 : [[fallthrough]];
1299 : default: {
1300 : // Default initialized StringBuilder: empty output.
1301 10 : mState = State::kDone;
1302 10 : hasLine = false;
1303 10 : break;
1304 : }
1305 : }
1306 :
1307 : // All the string should have fit based on the logic. It would be a public
1308 : // API invariant failure if this ever fails.
1309 78 : VerifyOrDie(mStringBuilder.Fit());
1310 :
1311 78 : return hasLine ? mStringBuilder.c_str() : nullptr;
1312 : }
1313 :
1314 : } // namespace Crypto
1315 : } // namespace chip
|