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