Coverage Report

Created: 2026-01-24 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openweave-core/src/test-apps/CASEOptions.cpp
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 2013-2017 Nest Labs, Inc.
4
 *    All rights reserved.
5
 *
6
 *    Licensed under the Apache License, Version 2.0 (the "License");
7
 *    you may not use this file except in compliance with the License.
8
 *    You may obtain a copy of the License at
9
 *
10
 *        http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *    Unless required by applicable law or agreed to in writing, software
13
 *    distributed under the License is distributed on an "AS IS" BASIS,
14
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 *    See the License for the specific language governing permissions and
16
 *    limitations under the License.
17
 */
18
19
/**
20
 *    @file
21
 *      Implementation of CASEConfig object, which provides an implementation of the WeaveCASEAuthDelegate
22
 *      interface for use in test applications.
23
 *
24
 */
25
26
#include "stdio.h"
27
28
#include "ToolCommon.h"
29
#include <Weave/Support/CodeUtils.h>
30
#include <Weave/Core/WeaveTLV.h>
31
#include <Weave/Profiles/WeaveProfiles.h>
32
#include <Weave/Profiles/security/WeaveSecurityDebug.h>
33
#include <Weave/Profiles/security/WeaveSig.h>
34
#include <Weave/Profiles/service-provisioning/ServiceProvisioning.h>
35
#include <Weave/Support/NestCerts.h>
36
#include <Weave/Support/ErrorStr.h>
37
#include <Weave/Support/ASN1.h>
38
#include <Weave/Support/Base64.h>
39
#include "CASEOptions.h"
40
41
using namespace nl::Weave;
42
using namespace nl::Weave::TLV;
43
using namespace nl::Weave::ASN1;
44
using namespace nl::Weave::Profiles;
45
using namespace nl::Weave::Profiles::Security;
46
using namespace nl::Weave::Profiles::Security::CASE;
47
48
CASEOptions gCASEOptions;
49
50
WEAVE_ERROR LoadCertsFromServiceConfig(const uint8_t *serviceConfig, uint16_t serviceConfigLen, WeaveCertificateSet& certSet)
51
0
{
52
0
    WEAVE_ERROR err;
53
0
    nl::Weave::TLV::TLVReader reader;
54
0
    TLVType topLevelContainer;
55
56
0
    reader.Init(serviceConfig, serviceConfigLen);
57
0
    reader.ImplicitProfileId = kWeaveProfile_ServiceProvisioning;
58
59
0
    err = reader.Next(kTLVType_Structure, ProfileTag(kWeaveProfile_ServiceProvisioning, ServiceProvisioning::kTag_ServiceConfig));
60
0
    SuccessOrExit(err);
61
62
0
    err = reader.EnterContainer(topLevelContainer);
63
0
    SuccessOrExit(err);
64
65
0
    err = reader.Next(kTLVType_Array, ContextTag(ServiceProvisioning::kTag_ServiceConfig_CACerts));
66
0
    SuccessOrExit(err);
67
68
0
    err = certSet.LoadCerts(reader, kDecodeFlag_IsTrusted);
69
0
    SuccessOrExit(err);
70
71
0
exit:
72
0
    return err;
73
0
}
74
75
bool ParseCASEConfig(const char *str, uint32_t& output)
76
0
{
77
0
    uint32_t configNum;
78
79
0
    if (!ParseInt(str, configNum))
80
0
        return false;
81
82
0
    switch (configNum)
83
0
    {
84
0
    case 1:
85
0
        output = kCASEConfig_Config1;
86
0
        return true;
87
0
    case 2:
88
0
        output = kCASEConfig_Config2;
89
0
        return true;
90
0
    default:
91
0
        return false;
92
0
    }
93
0
}
94
95
// Parse a sequence of zero or more unsigned integers corresponding to a list
96
// of allowed CASE configurations.  Integer values must be separated by either
97
// a comma or a space.
98
bool ParseAllowedCASEConfigs(const char *strConst, uint8_t& output)
99
0
{
100
0
    bool res = true;
101
0
    char *str = strdup(strConst);
102
0
    uint32_t configNum;
103
104
0
    output = 0;
105
106
0
    for (char *p = str; p != NULL; )
107
0
    {
108
0
        char *sep = strchr(p, ',');
109
0
        if (sep == NULL)
110
0
            sep = strchr(p, ' ');
111
112
0
        if (sep != NULL)
113
0
            *sep = 0;
114
115
0
        if (!ParseInt(p, configNum))
116
0
        {
117
0
            res = false;
118
0
            break;
119
0
        }
120
121
0
        if (configNum == 1)
122
0
            output |= kCASEAllowedConfig_Config1;
123
0
        else if (configNum == 2)
124
0
            output |= kCASEAllowedConfig_Config2;
125
0
        else
126
0
        {
127
0
            res = false;
128
0
            break;
129
0
        }
130
131
0
        p = (sep != NULL) ? sep + 1 : NULL;
132
0
    }
133
134
0
    free(str);
135
136
0
    return res;
137
0
}
138
139
CASEOptions::CASEOptions()
140
10
{
141
10
    static OptionDef optionDefs[] =
142
10
    {
143
10
#if WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
144
10
        { "node-cert",              kArgumentRequired,      kToolCommonOpt_NodeCert             },
145
10
        { "node-key",               kArgumentRequired,      kToolCommonOpt_NodeKey              },
146
10
        { "ca-cert",                kArgumentRequired,      kToolCommonOpt_CACert               },
147
10
        { "no-ca-cert",             kNoArgument,            kToolCommonOpt_NoCACert             },
148
10
        { "case-config",            kArgumentRequired,      kToolCommonOpt_CASEConfig           },
149
10
        { "allowed-case-configs",   kArgumentRequired,      kToolCommonOpt_AllowedCASEConfigs   },
150
10
        { "debug-case",             kNoArgument,            kToolCommonOpt_DebugCASE            },
151
10
#if WEAVE_CONFIG_SECURITY_TEST_MODE
152
10
        { "case-use-known-key",     kNoArgument,            kToolCommonOpt_CASEUseKnownECDHKey  },
153
10
#endif // WEAVE_CONFIG_SECURITY_TEST_MODE
154
10
#endif // WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
155
10
        { }
156
10
    };
157
10
    OptionDefs = optionDefs;
158
159
10
    HelpGroupName = "CASE OPTIONS";
160
161
10
    OptionHelp =
162
10
#if WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
163
10
        "  --node-cert <cert-file>\n"
164
10
        "       File containing a Weave certificate to be used to authenticate the node\n"
165
10
        "       when establishing a CASE session. The file can contain either raw TLV or\n"
166
10
        "       base-64.\n"
167
10
        "\n"
168
10
        "  --node-key <key-file>\n"
169
10
        "       File containing a private key to be used to authenticate the node\n"
170
10
        "       when establishing a CASE session. The file can contain either raw TLV or\n"
171
10
        "       base-64.\n"
172
10
        "\n"
173
10
        "  --ca-cert <cert-file>\n"
174
10
        "       File containing a Weave CA certificate to be included along with the\n"
175
10
        "       node's certificate when establishing a CASE session. The file can contain\n"
176
10
        "       either raw TLV or base-64.\n"
177
10
        "\n"
178
10
        "  --no-ca-cert\n"
179
10
        "       Do not send an intermediate certificate when establishing a CASE session.\n"
180
10
        "\n"
181
10
        "  --case-config <int>\n"
182
10
        "       Proposed the specified CASE configuration when initiating a CASE session.\n"
183
10
        "\n"
184
10
        "  --allowed-case-configs <int>[,<int>]\n"
185
10
        "       Accept the specified set of CASE configurations when either initiating or\n"
186
10
        "       responding to a CASE session.\n"
187
10
        "\n"
188
10
        "  --debug-case\n"
189
10
        "       Enable CASE debug messages.\n"
190
10
#if WEAVE_CONFIG_SECURITY_TEST_MODE
191
10
        "\n"
192
10
        "  --case-use-known-key\n"
193
10
        "       Enable use of known ECDH key in CASE.\n"
194
10
#endif // WEAVE_CONFIG_SECURITY_TEST_MODE
195
10
        "\n"
196
10
#endif // WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
197
10
        "";
198
199
    // Defaults
200
10
    InitiatorCASEConfig = kCASEConfig_NotSpecified;
201
10
    AllowedCASEConfigs = 0; // 0 causes code to use default value provided by WeaveSecurityManager
202
10
    NodeCert = NULL;
203
10
    NodeCertLength = 0;
204
10
    NodePrivateKey = NULL;
205
10
    NodePrivateKeyLength = 0;
206
10
    NodeIntermediateCert = NULL;
207
10
    NodeIntermediateCertLength = 0;
208
10
    ServiceConfig = NULL;
209
10
    ServiceConfigLength = 0;
210
10
    NodePayload = NULL;
211
10
    NodePayloadLength = 0;
212
10
    Debug = false;
213
10
#if WEAVE_CONFIG_SECURITY_TEST_MODE
214
10
    UseKnownECDHKey = false;
215
10
#endif
216
10
}
217
218
bool CASEOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
219
0
{
220
0
    switch (id)
221
0
    {
222
0
#if WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
223
224
0
    case kToolCommonOpt_NodeCert:
225
0
        if (!ReadCertFile(arg, (uint8_t *&)NodeCert, NodeCertLength))
226
0
            return false;
227
0
        break;
228
0
    case kToolCommonOpt_NodeKey:
229
0
        if (!ReadPrivateKeyFile(arg, (uint8_t *&)NodePrivateKey, NodePrivateKeyLength))
230
0
            return false;
231
0
        break;
232
0
    case kToolCommonOpt_CACert:
233
0
        if (!ReadCertFile(arg, (uint8_t *&)NodeIntermediateCert, NodeIntermediateCertLength))
234
0
            return false;
235
0
        break;
236
0
    case kToolCommonOpt_NoCACert:
237
0
        NodeIntermediateCert = NULL;
238
0
        NodeIntermediateCertLength = 0;
239
0
        break;
240
0
    case kToolCommonOpt_CASEConfig:
241
0
        if (!ParseCASEConfig(arg, InitiatorCASEConfig))
242
0
        {
243
0
            PrintArgError("%s: Invalid value specified for CASE config: %s\n", progName, arg);
244
0
            return false;
245
0
        }
246
0
        break;
247
0
    case kToolCommonOpt_AllowedCASEConfigs:
248
0
        if (!ParseAllowedCASEConfigs(arg, AllowedCASEConfigs))
249
0
        {
250
0
            PrintArgError("%s: Invalid value specified for allowed CASE configs: %s\n", progName, arg);
251
0
            return false;
252
0
        }
253
0
        break;
254
0
    case kToolCommonOpt_DebugCASE:
255
0
        Debug = true;
256
0
        break;
257
0
#if WEAVE_CONFIG_SECURITY_TEST_MODE
258
0
    case kToolCommonOpt_CASEUseKnownECDHKey:
259
0
        UseKnownECDHKey = true;
260
0
        break;
261
0
#endif //WEAVE_CONFIG_SECURITY_TEST_MODE
262
263
0
#endif // WEAVE_CONFIG_ENABLE_CASE_INITIATOR || WEAVE_CONFIG_ENABLE_CASE_RESPONDER
264
265
0
    default:
266
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
267
0
        return false;
268
0
    }
269
270
0
    return true;
271
0
}
272
273
bool CASEOptions::ReadCertFile(const char *fileName, uint8_t *& certBuf, uint16_t& certLen)
274
0
{
275
0
    uint32_t len;
276
277
0
    static const char *certB64Prefix = "1QAABAAB";
278
0
    static const size_t certB64PrefixLen = sizeof(certB64Prefix) - 1;
279
280
    // Read the specified file into a malloced buffer.
281
0
    certBuf = ReadFileArg(fileName, len, UINT16_MAX);
282
0
    if (certBuf == NULL)
283
0
        return false;
284
285
    // If the certificate is in base-64 format, convert it to raw TLV.
286
0
    if (len > certB64PrefixLen && memcmp(certBuf, certB64Prefix, certB64PrefixLen) == 0)
287
0
    {
288
0
        len = nl::Base64Decode((const char *)certBuf, len, (uint8_t *)certBuf);
289
0
        if (len == UINT16_MAX)
290
0
        {
291
0
            printf("Invalid certificate format: %s\n", fileName);
292
0
            free(certBuf);
293
0
            certBuf = NULL;
294
0
            return false;
295
0
        }
296
0
    }
297
298
0
    certLen = (uint16_t)len;
299
300
0
    return true;
301
0
}
302
303
bool CASEOptions::ReadPrivateKeyFile(const char *fileName, uint8_t *& keyBuf, uint16_t& keyLen)
304
0
{
305
0
    uint32_t len;
306
307
0
    static const char *keyB64Prefix = "1QAABAAC";
308
0
    static const size_t keyB64PrefixLen = sizeof(keyB64Prefix) - 1;
309
310
    // Read the specified file into a malloced buffer.
311
0
    keyBuf = ReadFileArg(fileName, len, UINT16_MAX);
312
0
    if (keyBuf == NULL)
313
0
        return false;
314
315
    // If the private key is in base-64 format, convert it to raw TLV.
316
0
    if (len > keyB64PrefixLen && memcmp(keyBuf, keyB64Prefix, keyB64PrefixLen) == 0)
317
0
    {
318
0
        len = nl::Base64Decode((const char *)keyBuf, len, (uint8_t *)keyBuf);
319
0
        if (len == UINT16_MAX)
320
0
        {
321
0
            printf("Invalid private key format: %s\n", fileName);
322
0
            free(keyBuf);
323
0
            keyBuf = NULL;
324
0
            return false;
325
0
        }
326
0
    }
327
328
0
    keyLen = (uint16_t)len;
329
330
0
    return true;
331
0
}
332
333
WEAVE_ERROR CASEOptions::GetNodeCert(const uint8_t *& nodeCert, uint16_t & nodeCertLen)
334
0
{
335
0
    nodeCert = NodeCert;
336
0
    nodeCertLen = NodeCertLength;
337
338
0
    if (nodeCert == NULL || nodeCertLen == 0)
339
0
    {
340
0
        if (!GetTestNodeCert(FabricState.LocalNodeId, nodeCert, nodeCertLen))
341
0
        {
342
0
            printf("ERROR: Node certificate not configured\n");
343
0
            return WEAVE_ERROR_CERT_NOT_FOUND;
344
0
        }
345
0
    }
346
0
    return WEAVE_NO_ERROR;
347
0
}
348
349
WEAVE_ERROR CASEOptions::GetNodePrivateKey(const uint8_t *& weavePrivKey, uint16_t& weavePrivKeyLen)
350
0
{
351
0
    weavePrivKey = NodePrivateKey;
352
0
    weavePrivKeyLen = NodePrivateKeyLength;
353
354
0
    if (weavePrivKey == NULL || weavePrivKeyLen == 0)
355
0
    {
356
0
        if (!GetTestNodePrivateKey(FabricState.LocalNodeId, weavePrivKey, weavePrivKeyLen))
357
0
        {
358
0
        printf("ERROR: Node private key not configured\n");
359
0
        return WEAVE_ERROR_KEY_NOT_FOUND;
360
0
        }
361
0
    }
362
0
    return WEAVE_NO_ERROR;
363
0
}
364
365
#if !WEAVE_CONFIG_LEGACY_CASE_AUTH_DELEGATE
366
367
WEAVE_ERROR CASEOptions::EncodeNodeCertInfo(const BeginSessionContext & msgCtx, TLVWriter & writer)
368
0
{
369
0
    WEAVE_ERROR err;
370
0
    const uint8_t * nodeCert;
371
0
    uint16_t nodeCertLen;
372
0
    const uint8_t * intermediateCert = NodeIntermediateCert;
373
0
    uint16_t intermediateCertLen = NodeIntermediateCertLength;
374
375
0
    if (intermediateCert == NULL || intermediateCertLen == 0)
376
0
    {
377
0
        intermediateCert = nl::NestCerts::Development::DeviceCA::Cert;
378
0
        intermediateCertLen = nl::NestCerts::Development::DeviceCA::CertLength;
379
0
    }
380
381
0
    err = GetNodeCert(nodeCert, nodeCertLen);
382
0
    SuccessOrExit(err);
383
384
0
    err = EncodeCASECertInfo(writer, nodeCert, nodeCertLen, intermediateCert, intermediateCertLen);
385
0
    SuccessOrExit(err);
386
387
0
exit:
388
0
    return err;
389
0
}
390
391
WEAVE_ERROR CASEOptions::GenerateNodeSignature(const BeginSessionContext & msgCtx,
392
        const uint8_t * msgHash, uint8_t msgHashLen, TLVWriter & writer, uint64_t tag)
393
0
{
394
0
    WEAVE_ERROR err;
395
0
    const uint8_t * nodePrivKey;
396
0
    uint16_t nodePrivKeyLen;
397
398
0
    err = GetNodePrivateKey(nodePrivKey, nodePrivKeyLen);
399
0
    SuccessOrExit(err);
400
401
0
    err = GenerateAndEncodeWeaveECDSASignature(writer, tag, msgHash, msgHashLen, nodePrivKey, nodePrivKeyLen);
402
0
    SuccessOrExit(err);
403
404
0
exit:
405
0
    return err;
406
0
}
407
408
WEAVE_ERROR CASEOptions::EncodeNodePayload(const BeginSessionContext & msgCtx,
409
        uint8_t * payloadBuf, uint16_t payloadBufSize, uint16_t & payloadLen)
410
0
{
411
0
    return GetNodePayload(msgCtx.IsInitiator(), payloadBuf, payloadBufSize, payloadLen);
412
0
}
413
414
WEAVE_ERROR CASEOptions::BeginValidation(const BeginSessionContext & msgCtx, ValidationContext & validCtx,
415
        WeaveCertificateSet & certSet)
416
0
{
417
0
    return BeginCertValidation(msgCtx.IsInitiator(), certSet, validCtx);
418
0
}
419
420
WEAVE_ERROR CASEOptions::HandleValidationResult(const BeginSessionContext & msgCtx, ValidationContext & validCtx,
421
        WeaveCertificateSet & certSet, WEAVE_ERROR & validRes)
422
0
{
423
0
    return HandleCertValidationResult(msgCtx.IsInitiator(), validRes, validCtx.SigningCert, msgCtx.PeerNodeId, certSet, validCtx);
424
0
}
425
426
void CASEOptions::EndValidation(const BeginSessionContext & msgCtx, ValidationContext & validCtx,
427
        WeaveCertificateSet & certSet)
428
0
{
429
0
    EndCertValidation(certSet, validCtx);
430
0
}
431
432
#else // !WEAVE_CONFIG_LEGACY_CASE_AUTH_DELEGATE
433
434
// Get the CASE Certificate Information structure for the local node.
435
WEAVE_ERROR CASEOptions::GetNodeCertInfo(bool isInitiator, uint8_t *buf, uint16_t bufSize, uint16_t& certInfoLen)
436
{
437
    WEAVE_ERROR err;
438
    const uint8_t *nodeCert;
439
    uint16_t nodeCertLen;
440
    const uint8_t * intCert = NodeIntermediateCert;
441
    uint16_t intCertLen = NodeIntermediateCertLength;
442
443
    if (intCert == NULL || intCertLen == 0)
444
    {
445
        intCert = nl::NestCerts::Development::DeviceCA::Cert;
446
        intCertLen = nl::NestCerts::Development::DeviceCA::CertLength;
447
    }
448
449
    err = GetNodeCert(nodeCert, nodeCertLen);
450
    SuccessOrExit(err);
451
452
    err = EncodeCASECertInfo(buf, bufSize, certInfoLen, nodeCert, nodeCertLen, intCert, intCertLen);
453
    SuccessOrExit(err);
454
455
exit:
456
    return err;
457
}
458
459
// Get the local node's private key.
460
WEAVE_ERROR CASEOptions::GetNodePrivateKey(bool isInitiator, const uint8_t *& weavePrivKey, uint16_t& weavePrivKeyLen)
461
{
462
    return GetNodePrivateKey(weavePrivKey, weavePrivKeyLen);
463
}
464
465
// Called when the CASE engine is done with the buffer returned by GetNodePrivateKey().
466
WEAVE_ERROR CASEOptions::ReleaseNodePrivateKey(const uint8_t *weavePrivKey)
467
{
468
    // nothing to do
469
    return WEAVE_NO_ERROR;
470
}
471
472
#endif // WEAVE_CONFIG_LEGACY_CASE_AUTH_DELEGATE
473
474
WEAVE_ERROR CASEOptions::GetNodePayload(bool isInitiator, uint8_t *buf, uint16_t bufSize, uint16_t& payloadLen)
475
0
{
476
0
    WEAVE_ERROR err = WEAVE_NO_ERROR;
477
478
0
    if (NodePayload != NULL)
479
0
    {
480
0
        VerifyOrExit(NodePayloadLength <= bufSize, err = WEAVE_ERROR_BUFFER_TOO_SMALL);
481
482
0
        memcpy(buf, NodePayload, NodePayloadLength);
483
0
        payloadLen = NodePayloadLength;
484
0
    }
485
486
0
    else
487
0
    {
488
0
        WeaveDeviceDescriptor deviceDesc;
489
0
        uint32_t encodedDescLen;
490
491
0
        gDeviceDescOptions.GetDeviceDesc(deviceDesc);
492
493
0
        err = WeaveDeviceDescriptor::EncodeTLV(deviceDesc, buf, bufSize, encodedDescLen);
494
0
        SuccessOrExit(err);
495
496
0
        payloadLen = encodedDescLen;
497
0
    }
498
499
0
exit:
500
0
    return err;
501
0
}
502
503
// Prepare the supplied certificate set and validation context for use in validating the certificate of a peer.
504
// This method is responsible for loading the trust anchors into the certificate set.
505
WEAVE_ERROR CASEOptions::BeginCertValidation(bool isInitiator, WeaveCertificateSet& certSet, ValidationContext& validContext)
506
0
{
507
0
    WEAVE_ERROR err;
508
0
    WeaveCertificateData *cert;
509
510
0
    err = certSet.Init(10, 1024);
511
0
    SuccessOrExit(err);
512
513
0
    if (ServiceConfig != NULL)
514
0
    {
515
0
        err = LoadCertsFromServiceConfig(ServiceConfig, ServiceConfigLength, certSet);
516
0
        SuccessOrExit(err);
517
518
        // Scan the list of trusted certs loaded from the service config.  If the list contains a general
519
        // certificate with a CommonName subject, presume this certificate is the access token certificate.
520
0
        for (uint8_t i = 0; i < certSet.CertCount; i++)
521
0
        {
522
0
            cert = &certSet.Certs[i];
523
0
            if ((cert->CertFlags & kCertFlag_IsTrusted) != 0 &&
524
0
                cert->CertType == kCertType_General &&
525
0
                cert->SubjectDN.AttrOID == ASN1::kOID_AttributeType_CommonName)
526
0
            {
527
0
                cert->CertType = kCertType_AccessToken;
528
0
            }
529
0
        }
530
0
    }
531
532
0
    else
533
0
    {
534
0
        err = certSet.LoadCert(nl::NestCerts::Development::Root::Cert, nl::NestCerts::Development::Root::CertLength, 0, cert);
535
0
        SuccessOrExit(err);
536
0
        cert->CertFlags |= kCertFlag_IsTrusted;
537
538
0
        err = certSet.LoadCert(nl::NestCerts::Production::Root::Cert, nl::NestCerts::Production::Root::CertLength, 0, cert);
539
0
        SuccessOrExit(err);
540
0
        cert->CertFlags |= kCertFlag_IsTrusted;
541
542
0
        const uint8_t *caCert;
543
0
        uint16_t caCertLen;
544
545
0
        GetTestCACert(TestMockRoot_CAId, caCert, caCertLen);
546
547
0
        err = certSet.LoadCert(caCert, caCertLen, 0, cert);
548
0
        SuccessOrExit(err);
549
0
        cert->CertFlags |= kCertFlag_IsTrusted;
550
551
0
        err = certSet.LoadCert(nl::NestCerts::Development::DeviceCA::Cert, nl::NestCerts::Development::DeviceCA::CertLength, kDecodeFlag_GenerateTBSHash, cert);
552
0
        SuccessOrExit(err);
553
554
0
        err = certSet.LoadCert(nl::NestCerts::Production::DeviceCA::Cert, nl::NestCerts::Production::DeviceCA::CertLength, kDecodeFlag_GenerateTBSHash, cert);
555
0
        SuccessOrExit(err);
556
557
0
        GetTestCACert(TestMockServiceEndpointCA_CAId, caCert, caCertLen);
558
559
0
        err = certSet.LoadCert(caCert, caCertLen, kDecodeFlag_GenerateTBSHash, cert);
560
0
        SuccessOrExit(err);
561
0
    }
562
563
0
    memset(&validContext, 0, sizeof(validContext));
564
0
    validContext.EffectiveTime = SecondsSinceEpochToPackedCertTime(time(NULL));
565
0
    validContext.RequiredKeyUsages = kKeyUsageFlag_DigitalSignature;
566
0
    validContext.RequiredKeyPurposes = (isInitiator) ? kKeyPurposeFlag_ServerAuth : kKeyPurposeFlag_ClientAuth;
567
568
0
    if (Debug)
569
0
    {
570
0
        validContext.CertValidationResults = (WEAVE_ERROR *)malloc(sizeof(WEAVE_ERROR) * certSet.MaxCerts);
571
0
        validContext.CertValidationResultsLen = certSet.MaxCerts;
572
0
    }
573
574
0
exit:
575
0
    return err;
576
0
}
577
578
// Called when peer certificate validation is complete.
579
WEAVE_ERROR CASEOptions::HandleCertValidationResult(bool isInitiator, WEAVE_ERROR& validRes, WeaveCertificateData *peerCert,
580
        uint64_t peerNodeId, WeaveCertificateSet& certSet, ValidationContext& validContext)
581
0
{
582
    // If the peer's certificate is otherwise valid...
583
0
    if (validRes == WEAVE_NO_ERROR)
584
0
    {
585
        // If the peer authenticated with a device certificate...
586
0
        if (peerCert->CertType == kCertType_Device)
587
0
        {
588
            // Get the node id from the certificate subject.
589
0
            uint64_t certId = peerCert->SubjectDN.AttrValue.WeaveId;
590
591
            // This is a work-around for DVT devices that were built with incorrect certificates.
592
            // Specifically, the device id in the certificate didn't include Nest's OUI (the first
593
            // 3 bytes of the EUI-64 that makes up the id). Here we grandfather these in by assuming
594
            // anything that has an OUI of 0 is in fact a Nest device.
595
0
            if ((certId & 0xFFFFFF0000000000ULL) == 0)
596
0
                certId |= 0x18b4300000000000ULL;
597
598
            // Verify the certificate node id matches the peer's node id.
599
0
            if (certId != peerNodeId)
600
0
                validRes = WEAVE_ERROR_WRONG_CERT_SUBJECT;
601
0
        }
602
603
        // If the peer authenticated with a service endpoint certificate...
604
0
        else if (peerCert->CertType == kCertType_ServiceEndpoint)
605
0
        {
606
            // Get the node id from the certificate subject.
607
0
            uint64_t certId = peerCert->SubjectDN.AttrValue.WeaveId;
608
609
            // Verify the certificate node id matches the peer's node id.
610
0
            if (certId != peerNodeId)
611
0
                validRes = WEAVE_ERROR_WRONG_CERT_SUBJECT;
612
613
            // Reject the peer if they are initiating the session.  Service endpoint certificates
614
            // cannot be used to initiate sessions to other nodes, only to respond.
615
0
            if (!isInitiator)
616
0
                validRes = WEAVE_ERROR_WRONG_CERT_TYPE;
617
0
        }
618
619
        // If the peer authenticated with an access token certificate...
620
0
        else if (peerCert->CertType == kCertType_AccessToken)
621
0
        {
622
            // Reject the peer if they are the session responder.  Access token certificates
623
            // can only be used to initiate sessions.
624
0
            if (isInitiator)
625
0
                validRes = WEAVE_ERROR_WRONG_CERT_TYPE;
626
0
        }
627
628
        // For all other certificate types, reject the session.
629
0
        else
630
0
        {
631
0
            validRes = WEAVE_ERROR_WRONG_CERT_TYPE;
632
0
        }
633
0
    }
634
635
0
    if (Debug)
636
0
    {
637
0
        if (validRes == WEAVE_NO_ERROR)
638
0
            printf("Certificate validation completed successfully\n");
639
0
        else
640
0
            printf("Certificate validation failed: %s\n", nl::ErrorStr(validRes));
641
642
0
        if (peerCert != NULL)
643
0
            printf("Peer certificate: %d\n", (int)(peerCert - certSet.Certs));
644
645
0
        printf("\nValidation results:\n\n");
646
0
        PrintCertValidationResults(stdout, certSet, validContext, 2);
647
0
    }
648
649
0
    return WEAVE_NO_ERROR;
650
0
}
651
652
// Called when peer certificate validation is complete.
653
WEAVE_ERROR CASEOptions::EndCertValidation(WeaveCertificateSet& certSet, ValidationContext& validContext)
654
0
{
655
0
    if (Debug)
656
0
        free(validContext.CertValidationResults);
657
0
    return WEAVE_NO_ERROR;
658
0
}