Skip to content

Commit

Permalink
PoC CCM Joiner
Browse files Browse the repository at this point in the history
  • Loading branch information
EskoDijk committed May 12, 2024
1 parent 383d0d2 commit 1129d83
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 7 deletions.
11 changes: 11 additions & 0 deletions include/openthread/joiner.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ otError otJoinerStart(otInstance *aInstance,
otJoinerCallback aCallback,
void *aContext);

/**
* FIXME documentation
*/
void otJoinerSetCcmIdentity(otInstance *aInstance,
const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength);

/**
* Disables the Thread Joiner role.
*
Expand Down
68 changes: 67 additions & 1 deletion src/cli/cli_joiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,41 @@

#if OPENTHREAD_CONFIG_JOINER_ENABLE

#define OT_CLI_IDEVID_X509_CERT \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIBmDCCAT+gAwIBAgIEAQIDBDAKBggqhkjOPQQDAjBvMQswCQYDVQQGEwJYWDEQ\r\n" \
"MA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQLEwZNeVVu\r\n" \
"aXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5kb3IuY29t\r\n" \
"MB4XDTIzMTAxNjEwMzk1NFoXDTI0MTAxNjEwMzk1NFowIjEgMB4GA1UEAxMXbXl2\r\n" \
"ZW5kb3IuY29tL3RjYXQvbXlkZXYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB\r\n" \
"aWwFDNj1bpQIdN+Kp2cHWw55U/+fa+OmZnoy1B4BOT+822jdwPBuyXWAQoBdYdQJ\r\n" \
"ff4RgmhczyV4PhArPIuAoxYwFDASBgkrBgEEAYLfKgMEBQABAQEBMAoGCCqGSM49\r\n" \
"BAMCA0cAMEQCIBEHxiEDij26y6V77Q311Gj4CZAuZuPGXZpnzL2BLk7bAiAlFk6G\r\n" \
"mYGzkcrYyssFI9HlPgrisWoMmgummaTtCuvrEw==\r\n" \
"-----END CERTIFICATE-----\r\n"

#define OT_CLI_IDEVID_PRIV_KEY \
"-----BEGIN EC PRIVATE KEY-----\r\n" \
"MHcCAQEEIDeJ6lVQKiOIBxKwTZp6TkU5QVHt9pvXOR9CGpPBI3DhoAoGCCqGSM49\r\n" \
"AwEHoUQDQgAEAWlsBQzY9W6UCHTfiqdnB1sOeVP/n2vjpmZ6MtQeATk/vNto3cDw\r\n" \
"bsl1gEKAXWHUCX3+EYJoXM8leD4QKzyLgA==\r\n" \
"-----END EC PRIVATE KEY-----\r\n"

#define OT_CLI_IDEVID_CA_X509_CERT_CHAIN \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIICCDCCAa2gAwIBAgIJAIKxygBXoH+5MAoGCCqGSM49BAMCMG8xCzAJBgNVBAYT\r\n" \
"AlhYMRAwDgYDVQQIEwdNeVN0YXRlMQ8wDQYDVQQHEwZNeUNpdHkxDzANBgNVBAsT\r\n" \
"Bk15VW5pdDERMA8GA1UEChMITXlWZW5kb3IxGTAXBgNVBAMTEHd3dy5teXZlbmRv\r\n" \
"ci5jb20wHhcNMjMxMDE2MTAzMzE1WhcNMjYxMDE2MTAzMzE1WjBvMQswCQYDVQQG\r\n" \
"EwJYWDEQMA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQL\r\n" \
"EwZNeVVuaXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5k\r\n" \
"b3IuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdyzPAXGKeZY94OhHAWX\r\n" \
"HzJfQIjGSyaOzlgL9OEFw2SoUDncLKPGwfPAUSfuMyEkzszNDM0HHkBsDLqu4n25\r\n" \
"/6MyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU4EynoSw9eDKZEVPkums2\r\n" \
"IWLAJCowCgYIKoZIzj0EAwIDSQAwRgIhAMYGGL9xShyE6P9wEU+MAYF6W3CzdrwV\r\n" \
"kuerX1encIH2AiEA5rq490NUobM1Au43roxJq1T6Z43LscPVbGZfULD1Jq0=\r\n" \
"-----END CERTIFICATE-----\r\n"

namespace ot {
namespace Cli {

Expand Down Expand Up @@ -169,6 +204,37 @@ template <> otError Joiner::Process<Cmd("start")>(Arg aArgs[])
return error;
}

/**
* @cli joiner ccm
* @code
* joiner ccm
* Done
* @endcode
* @cparam joiner ccm [@ca{provisioning-url}]
* * `provisioning-url`: Provisioning URL for the %Joiner (optional).
* @par api_copy
* #otJoinerCcm
*/
template <> otError Joiner::Process<Cmd("ccm")>(Arg aArgs[])
{
otError error;

otJoinerSetCcmIdentity(GetInstancePtr(),
reinterpret_cast<const uint8_t *>(OT_CLI_IDEVID_X509_CERT), sizeof(OT_CLI_IDEVID_X509_CERT),
reinterpret_cast<const uint8_t *>(OT_CLI_IDEVID_PRIV_KEY), sizeof(OT_CLI_IDEVID_PRIV_KEY),
reinterpret_cast<const uint8_t *>(OT_CLI_IDEVID_CA_X509_CERT_CHAIN), sizeof(OT_CLI_IDEVID_CA_X509_CERT_CHAIN));
error = otJoinerStart(GetInstancePtr(),
nullptr, // aPskd -> not used - instead, certificate
aArgs[0].GetCString(), // aProvisioningUrl (`nullptr` if aArgs[0] is empty)
PACKAGE_NAME, // aVendorName
OPENTHREAD_CONFIG_PLATFORM_INFO, // aVendorModel
PACKAGE_VERSION, // aVendorSwVersion
nullptr, // aVendorData
&Joiner::HandleCallback, this);

return error;
}

/**
* @cli joiner stop
* @code
Expand Down Expand Up @@ -222,7 +288,7 @@ otError Joiner::Process(Arg aArgs[])
}

static constexpr Command kCommands[] = {
CmdEntry("discerner"), CmdEntry("id"), CmdEntry("start"), CmdEntry("state"), CmdEntry("stop"),
CmdEntry("ccm"), CmdEntry("discerner"), CmdEntry("id"), CmdEntry("start"), CmdEntry("state"), CmdEntry("stop"),
};

#undef CmdEntry
Expand Down
13 changes: 13 additions & 0 deletions src/core/api/joiner_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@

using namespace ot;

void otJoinerSetCcmIdentity(otInstance *aInstance,
const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength)
{
AsCoreType(aInstance).Get<MeshCoP::Joiner>().SetCcmIdentity(aX509Cert, aX509Length, aPrivateKey,
aPrivateKeyLength, aX509CaCertificateChain,
aX509CaCertChainLength);
}

otError otJoinerStart(otInstance *aInstance,
const char *aPskd,
const char *aProvisioningUrl,
Expand Down
42 changes: 38 additions & 4 deletions src/core/meshcop/border_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,16 +410,35 @@ template <> void BorderAgent::HandleTmf<kUriRelayRx>(Coap::Message &aMessage, co

Coap::Message *message = nullptr;
Error error = kErrorNone;
uint16_t joinerPort;

VerifyOrExit(mState != kStateStopped);

VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);

message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriRelayRx);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
// determine type of relaying, based on Relay Type ID (in Joiner's UDP source port)
// TODO only do this when CCM flag is 1 in Security Policy
// TODO get stored context based on Joiner IID / port etc -> allow pure DTLS to go outside BA.
SuccessOrExit(error = Tlv::Find<JoinerUdpPortTlv>(aMessage, joinerPort));
switch(joinerPort & 0x000f) {
case 2: // BRSKI
// create new UDP message to Registrar - with DTLS payload in.
// TODO
message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriRelayRx);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);

SuccessOrExit(error = ForwardToRegistrar(*message, aMessage));
LogInfo("Sent to Registrar on RelayRx (c/rx)");
break;
case 9: // MeshCoP
message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriRelayRx);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);

SuccessOrExit(error = ForwardToCommissioner(*message, aMessage));
LogInfo("Sent to commissioner on RelayRx (c/rx)");
break;
}

SuccessOrExit(error = ForwardToCommissioner(*message, aMessage));
LogInfo("Sent to commissioner on RelayRx (c/rx)");

exit:
FreeMessageOnError(message, error);
Expand All @@ -440,6 +459,21 @@ Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const M
return error;
}

Error BorderAgent::ForwardToRegistrar(Coap::Message &aForwardMessage, const Message &aMessage)
{
Error error;

SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, aMessage.GetOffset(),
aMessage.GetLength() - aMessage.GetOffset()));
SuccessOrExit(error = SendMessage(aForwardMessage));

LogInfo("Sent to Registrar");

exit:
LogWarnOnError(error, "send to Registrar");
return error;
}

template <>
void BorderAgent::HandleTmf<kUriCommissionerPetition>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
Expand Down
1 change: 1 addition & 0 deletions src/core/meshcop/border_agent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ class BorderAgent : public InstanceLocator, private NonCopyable
void HandleCoapResponse(const ForwardContext &aForwardContext, const Coap::Message *aResponse, Error aResult);
Error ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri);
Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage);
Error ForwardToRegistrar(Coap::Message &aForwardMessage, const Message &aMessage);
static bool HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo);
bool HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);

Expand Down
21 changes: 19 additions & 2 deletions src/core/meshcop/joiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@ void Joiner::SetState(State aState)
return;
}

void Joiner::SetCcmIdentity(const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength)
{
Get<Tmf::SecureAgent>().SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength);
Get<Tmf::SecureAgent>().SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength);
}

Error Joiner::Start(const char *aPskd,
const char *aProvisioningUrl,
const char *aVendorName,
Expand All @@ -145,15 +156,21 @@ Error Joiner::Start(const char *aPskd,
VerifyOrExit(Get<ThreadNetif>().IsUp() && Get<Mle::Mle>().GetRole() == Mle::kRoleDisabled,
error = kErrorInvalidState);

SuccessOrExit(error = joinerPskd.SetFrom(aPskd));
if (aPskd != nullptr)
{
SuccessOrExit(error = joinerPskd.SetFrom(aPskd));
}

// Use random-generated extended address.
randomAddress.GenerateRandom();
Get<Mac::Mac>().SetExtAddress(randomAddress);
Get<Mle::MleRouter>().UpdateLinkLocalAddress();

SuccessOrExit(error = Get<Tmf::SecureAgent>().Start(kJoinerUdpPort));
Get<Tmf::SecureAgent>().SetPsk(joinerPskd);
if (aPskd != nullptr)
{
Get<Tmf::SecureAgent>().SetPsk(joinerPskd);
}

for (JoinerRouter &router : mJoinerRouters)
{
Expand Down
10 changes: 10 additions & 0 deletions src/core/meshcop/joiner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ class Joiner : public InstanceLocator, private NonCopyable
*/
Error ClearDiscerner(void);

/**
* FIXME comments insert here from coap_secure.hpp
*/
void SetCcmIdentity(const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength);

/**
* Converts a given Joiner state to its human-readable string representation.
*
Expand Down

0 comments on commit 1129d83

Please sign in to comment.