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