1#ifndef NDNPH_APP_NDNCERT_CLIENT_HPP
2#define NDNPH_APP_NDNCERT_CLIENT_HPP
5#include "../../face/packet-handler.hpp"
45 void (*cb)(
void*,
bool),
void* arg) = 0;
48using ChallengeList = std::array<Challenge*, detail::MaxChallenges::value>;
69 EvDecoder::def<TT::CaPrefix>([&](
const Decoder::Tlv& d) {
70 if (!d.vd().decode(prefix) || data.getName().getPrefix(-4) != prefix) {
73 prefix = prefix.clone(region);
76 EvDecoder::defIgnore<TT::CaInfo>(), EvDecoder::defIgnore<TT::ParameterKey, true>(),
77 EvDecoder::defNni<TT::MaxValidityPeriod>(&maxValidityPeriod),
78 EvDecoder::def<TT::CaCertificate>([&](
const Decoder::Tlv& d) {
108 if (!encoder || !name || !interest) {
128 hasChallenge.reset();
130 EvDecoder::decodeValue(
132 EvDecoder::def<TT::Salt>([
this](
const Decoder::Tlv& d) {
133 if (d.length == sizeof(salt)) {
134 std::copy_n(d.value, d.length, salt);
139 EvDecoder::def<TT::RequestId>([
this](
const Decoder::Tlv& d) {
140 if (d.
length ==
sizeof(requestId)) {
146 EvDecoder::def<TT::Challenge, true>([
this, &challenges](
const Decoder::Tlv& d) {
147 for (
size_t i = 0; i < challenges.size(); ++i) {
148 const Challenge* ch = challenges[i];
152 if (ch->getId() == tlv::Value(d.
value, d.
length)) {
180 [
this](
Encoder& encoder) { encoder.
prependTlv(TT::SelectedChallenge, challenge->getId()); },
189 Component(region, detail::RequestIdLen::value, requestId));
191 if (!encrypted || !name || !interest) {
196 return interest.
parameterize(encrypted).
sign(signer, region, signingPolicy);
215 uint32_t remainingTime = 0;
218 !!decrypted && EvDecoder::decodeValue(
219 decrypted.makeDecoder(), EvDecoder::defNni<TT::Status, tlv::NNI, 1>(&status),
220 EvDecoder::def<TT::ChallengeStatus, false, 2>(&challengeStatus),
221 EvDecoder::defNni<TT::RemainingTries, tlv::NNI, 3>(&remainingTries),
222 EvDecoder::defNni<TT::RemainingTime, tlv::NNI, 4>(&remainingTime),
223 EvDecoder::def<TT::ParameterKey, true, 5>(
224 [&](
const Decoder::Tlv& d) { return paramsParser.parseKey(d); }),
225 EvDecoder::def<TT::ParameterValue, true, 5>(
226 [&](
const Decoder::Tlv& d) { return paramsParser.parseValue(d); }),
227 EvDecoder::def<TT::IssuedCertName, false, 6>(
228 [
this](
const Decoder::Tlv& d) { return d.vd().decode(issuedCertName); }),
229 EvDecoder::def<TT::ForwardingHint, false, 7>([
this](
const Decoder::Tlv& d) {
230 return detail::decodeFwHint(d, &fwHint);
235 expireTime = port::Clock::add(port::Clock::now(), remainingTime * 1000);
283 SendChallengeRequest,
284 WaitChallengeResponse,
293 explicit GotoState(
Client* client)
294 : m_client(client) {}
296 bool operator()(State state) {
298 static_cast<int>(state));
299 m_client->m_state = state;
307 static_cast<int>(State::Failure));
308 m_client->m_state = State::Failure;
313 Client* m_client =
nullptr;
317 explicit Client(
const Options& opts)
318 : PacketHandler(opts.face)
320 , m_profile(opts.profile)
321 , m_challenges(opts.challenges)
324 , m_cbCtx(opts.ctx) {
325 sendNewRequest(opts.pub);
330 case State::SendChallengeRequest: {
331 sendChallengeRequest();
334 case State::FetchIssuedCert: {
338 case State::WaitNewResponse:
339 case State::WaitChallengeResponse:
340 case State::WaitIssuedCert: {
341 if (m_pending.expired()) {
342 m_state = State::Failure;
346 case State::Success: {
350 case State::Failure: {
351 m_cb(m_cbCtx,
Data());
361 if (!m_pending.matchPitToken()) {
366 case State::WaitNewResponse: {
367 return handleNewResponse(data);
369 case State::WaitChallengeResponse: {
370 return handleChallengeResponse(data);
372 case State::WaitIssuedCert: {
373 return handleIssuedCert(data);
383 GotoState gotoState(
this);
384 int res = mbedtls_ecdh_gen_public(mbedtls::P256::group(), m_ecdhPvt, m_newRequest.ecdhPub,
385 mbedtls::rng,
nullptr);
391 auto validity = certificate::getValidity(m_profile.cert)
392 .intersect(ValidityPeriod::secondsFromNow(m_profile.maxValidityPeriod));
393 if (!validity.includesUnix()) {
398 auto cert = pub.
selfSign(m_region, validity, m_pvt);
399 m_newRequest.certRequest = m_region.create<
Data>();
400 if (!m_newRequest.certRequest || !m_newRequest.certRequest.decodeFrom(cert)) {
405 m_pending.send(m_newRequest.toInterest(region, m_profile, m_signingPolicy, m_pvt)) &&
406 gotoState(State::WaitNewResponse);
409 bool handleNewResponse(Data data) {
410 bool ok = m_newResponse.fromData(m_region, data, m_profile, m_challenges);
416 GotoState gotoState(
this);
417 for (
size_t i = 0; i < m_newResponse.hasChallenge.size(); ++i) {
418 if (m_newResponse.hasChallenge.test(i)) {
419 m_challengeRequest.challenge = m_challenges[i];
423 if (m_challengeRequest.challenge ==
nullptr) {
428 ok = m_sessionKey.makeKey(m_ecdhPvt, m_newResponse.ecdhPub, m_newResponse.salt,
429 m_newResponse.requestId);
434 prepareChallengeRequest(gotoState);
438 static void challengeCallback(
void* self,
bool ok) {
439 static_cast<Client*
>(self)->m_state = ok ? State::SendChallengeRequest : State::Failure;
442 void prepareChallengeRequest(GotoState& gotoState) {
443 gotoState(State::ExecuteChallenge);
444 m_challengeRequest.params.clear();
445 if (m_challengeResponse.status == Status::BEFORE_CHALLENGE) {
446 m_challengeRequest.challenge->start(m_challengeRegion, m_challengeRequest, challengeCallback,
449 m_challengeRequest.challenge->next(m_challengeRegion, m_challengeResponse, m_challengeRequest,
450 challengeCallback,
this);
454 void sendChallengeRequest() {
455 StaticRegion<2048> region;
456 GotoState gotoState(
this);
457 m_pending.send(m_challengeRequest.toInterest(region, m_profile, m_newResponse.requestId,
458 m_sessionKey, m_signingPolicy, m_pvt)) &&
459 gotoState(State::WaitChallengeResponse);
462 bool handleChallengeResponse(Data data) {
463 m_challengeRegion.reset();
464 bool ok = m_challengeResponse.fromData(m_challengeRegion, data, m_profile,
465 m_newResponse.requestId, m_sessionKey);
471 GotoState gotoState(
this);
472 switch (m_challengeResponse.status) {
473 case Status::CHALLENGE:
474 prepareChallengeRequest(gotoState);
476 case Status::SUCCESS:
477 return gotoState(State::FetchIssuedCert);
484 void sendFetchInterest() {
486 GotoState gotoState(
this);
489 interest.setName(m_challengeResponse.issuedCertName);
490 interest.setFwHint(m_challengeResponse.fwHint);
491 m_pending.send(interest) && gotoState(State::WaitIssuedCert);
494 bool handleIssuedCert(Data data) {
496 if (data.getFullName(region) != m_challengeResponse.issuedCertName) {
501 GotoState gotoState(
this);
502 if (!ec::isCertificate(data)) {
507 return gotoState(State::Success);
511 OutgoingPendingInterest m_pending;
512 State m_state = State::SendNewRequest;
514 const CaProfile& m_profile;
520 StaticRegion<2048> m_region;
521 StaticRegion<512> m_challengeRegion;
522 detail::ISigPolicy m_signingPolicy;
523 mbedtls::Mpi m_ecdhPvt;
524 NewRequest m_newRequest;
525 NewResponse m_newResponse;
526 detail::SessionKey m_sessionKey;
527 ChallengeRequest m_challengeRequest;
528 ChallengeResponse m_challengeResponse;
535 return challenge_consts::nop();
543 void* arg)
override {
552 : m_cert(std::move(cert))
553 , m_signer(signer) {}
556 return challenge_consts::possession();
560 void* arg)
override {
570 request.params.set(challenge_consts::issuedcert(),
tlv::Value(encoder));
575 void (*cb)(
void*,
bool),
void* arg)
override {
576 tlv::Value nonce = response.params.get(challenge_consts::nonce());
577 uint8_t* sig = region.
alloc(m_signer.getMaxSigLen());
578 if (nonce.
size() != 16 || sig ==
nullptr) {
584 ssize_t sigLen = m_signer.sign({nonce}, sig);
591 request.params.set(challenge_consts::proof(),
tlv::Value(sig, sigLen));
#define NDNPH_NDNCERT_LOG(...)
Definition common.hpp:15
Name component.
Definition component.hpp:16
Data packet.
Definition data.hpp:136
tlv::Value getContent() const
Definition data.hpp:172
const Name & getName() const
Definition data.hpp:140
bool verify(const PublicKey &key) const
Verify the packet with a public key.
Definition data.hpp:263
bool decodeFrom(const Decoder::Tlv &input)
Decode packet.
Definition data.hpp:201
Decoded TLV.
Definition decoder.hpp:13
size_t length
Definition decoder.hpp:39
const uint8_t * value
Definition decoder.hpp:40
TLV encoder that accepts items in reverse order.
Definition encoder.hpp:10
bool prepend(const First &first, const Arg &... arg)
Prepend a sequence of values.
Definition encoder.hpp:123
void trim() const
Release unused space to the Region.
Definition encoder.hpp:58
bool prependTlv(uint32_t type, OmitEmptyTag omitEmpty, const Arg &... arg)
Prepend TLV, measuring TLV-LENGTH automatically.
Definition encoder.hpp:143
static bool decodeValue(const Decoder &input, const E &... defs)
Decode input TLV-VALUE with a sequence of element definitions.
Definition ev-decoder.hpp:126
Network layer face.
Definition face.hpp:12
Signed sign(const PrivateKey &key, ISigInfo sigInfo=ISigInfo()) const
Definition interest.hpp:350
Interest packet.
Definition interest.hpp:284
Parameterized parameterize(tlv::Value appParameters) const
Add AppParameters to the packet.
Definition interest.hpp:374
void setMustBeFresh(bool v)
Definition interest.hpp:296
void setName(const Name &v)
Definition interest.hpp:288
Name.
Definition name.hpp:14
size_t size() const
Get number of components.
Definition name.hpp:86
Base class to receive packets from Face.
Definition packet-handler.hpp:10
Private key.
Definition private-key.hpp:9
Region-based memory allocator thats owns memory of NDNph objects.
Definition region.hpp:9
RefType create(Arg &&... arg)
Allocate and create an object, and return its reference.
Definition region.hpp:90
uint8_t * alloc(size_t size)
Allocate a buffer with no alignment requirement.
Definition region.hpp:27
Region with statically allocated memory.
Definition region.hpp:143
Definition convention.hpp:111
Definition interest.hpp:206
EC private key.
Definition ec.hpp:180
EC public key.
Definition ec.hpp:65
bool import(const Name &name, const uint8_t raw[KeyLen::value])
Import from raw key bits.
Definition ec.hpp:80
Data::Signed selfSign(Region ®ion, const ValidityPeriod &validity, const Signer &signer) const
Generate self-signed certificate of this public key.
Definition ec.hpp:154
CA profile packet.
Definition client.hpp:51
static bool isName(const Name &name)
Determine whether name is a valid CA profile packet name.
Definition client.hpp:54
bool fromData(Region ®ion, const Data &data)
Extract CA profile from Data packet.
Definition client.hpp:65
EcPublicKey pub
CA public key.
Definition client.hpp:88
CHALLENGE request packet.
Definition client.hpp:166
Interest::Signed toInterest(Region ®ion, const CaProfile &profile, const uint8_t *requestId, detail::SessionKey &sessionKey, detail::ISigPolicy &signingPolicy, const EcPrivateKey &signer) const
Build CHALLENGE request packet.
Definition client.hpp:174
CHALLENGE response packet.
Definition client.hpp:201
bool fromData(Region ®ion, const Data &data, const CaProfile &profile, const uint8_t *requestId, detail::SessionKey &sessionKey)
Extract CHALLENGE response from Data packet.
Definition client.hpp:208
Client side of a challenge.
Definition client.hpp:22
virtual void start(Region ®ion, ChallengeRequest &request, void(*cb)(void *, bool), void *arg)=0
Create a message to select and start the challenge.
virtual ~Challenge()=default
virtual tlv::Value getId() const =0
Return challenge identifier.
virtual void next(Region ®ion, const ChallengeResponse &response, ChallengeRequest &request, void(*cb)(void *, bool), void *arg)=0
Create a message to continue the challenge.
Client application.
Definition client.hpp:241
bool processData(Data data) final
Override to receive Data packets.
Definition client.hpp:360
void loop() final
Override to be invoked periodically.
Definition client.hpp:328
static void requestCertificate(const Options &opts)
Request a certificate.
Definition client.hpp:274
void(*)(void *ctx, Data cert) Callback
Callback to be invoked upon completion of a certificate request procedure.
Definition client.hpp:248
NEW request packet.
Definition client.hpp:92
Interest::Signed toInterest(Region ®ion, const CaProfile &profile, detail::ISigPolicy &signingPolicy, const EcPrivateKey &signer) const
Build NEW request packet.
Definition client.hpp:99
NEW response packet.
Definition client.hpp:118
std::bitset< detail::MaxChallenges::value > hasChallenge
List of client challenges offered by server.
Definition client.hpp:162
bool fromData(Region &, const Data &data, const CaProfile &profile, const ChallengeList &challenges)
Extract NEW response from Data packet.
Definition client.hpp:126
The "nop" challenge where the server would approve every request.
Definition client.hpp:532
void start(Region &, ChallengeRequest &, void(*cb)(void *, bool), void *arg) override
Create a message to select and start the challenge.
Definition client.hpp:538
void next(Region &, const ChallengeResponse &, ChallengeRequest &, void(*cb)(void *, bool), void *arg) override
Create a message to continue the challenge.
Definition client.hpp:542
tlv::Value getId() const override
Return challenge identifier.
Definition client.hpp:534
The "possession" challenge where client must present an existing certificate.
Definition client.hpp:549
void start(Region ®ion, ChallengeRequest &request, void(*cb)(void *, bool), void *arg) override
Create a message to select and start the challenge.
Definition client.hpp:559
void next(Region ®ion, const ChallengeResponse &response, ChallengeRequest &request, void(*cb)(void *, bool), void *arg) override
Create a message to continue the challenge.
Definition client.hpp:574
tlv::Value getId() const override
Return challenge identifier.
Definition client.hpp:555
PossessionChallenge(Data cert, const PrivateKey &signer)
Definition client.hpp:551
Symmetric key used in CHALLENGE step.
Definition common.hpp:33
tlv::Value decrypt(Region ®ion, tlv::Value message, const uint8_t *requestId)
Decrypt from encrypted-message.
Definition common.hpp:53
tlv::Value encrypt(Region ®ion, tlv::Value plaintext, const uint8_t *requestId)
Encrypt to encrypted-message.
Definition common.hpp:48
A sequence of bytes, usually TLV-VALUE.
Definition value.hpp:11
Decoder makeDecoder() const
Create a Decoder over this value buffer.
Definition value.hpp:64
size_t size() const
Definition value.hpp:46
#define NDNPH_ASSERT(x)
Definition common.hpp:30
std::array< Challenge *, detail::MaxChallenges::value > ChallengeList
Definition client.hpp:48
Component getInfoComponent()
Return 'INFO' component.
Definition an.hpp:53
client::Client Client
Definition client.hpp:602
Component getCaComponent()
Return 'CA' component.
Definition an.hpp:45
Component getNewComponent()
Return 'NEW' component.
Definition an.hpp:69
Component getChallengeComponent()
Return 'CHALLENGE' component.
Definition an.hpp:77
ec::EcPrivateKey EcPrivateKey
Definition ec.hpp:326
Definition client.hpp:250
Face & face
Face for communication.
Definition client.hpp:252
void * ctx
Context pointer.
Definition client.hpp:270
const EcPrivateKey & pvt
Corresponding private key.
Definition client.hpp:264
Callback cb
Completion callback.
Definition client.hpp:267
const EcPublicKey & pub
Public key to appear in the certificate.
Definition client.hpp:261
const ChallengeList & challenges
List of acceptable challenges.
Definition client.hpp:258
const CaProfile & profile
CA profile.
Definition client.hpp:255