Skip to content

Commit 85f9cb6

Browse files
committed
convert shared_secret_message signer into an implementation class.
1 parent 3437e37 commit 85f9cb6

File tree

3 files changed

+138
-117
lines changed

3 files changed

+138
-117
lines changed

sdk/src/signaling_util/message_transport/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
set(curl_src
22
src/message_transport.cpp
33
src/message_transport_impl.cpp
4+
src/shared_secret_message_signer_impl.cpp
45
)
56

67
add_library( nabto_webrtc_message_transport "${curl_src}")
@@ -24,4 +25,3 @@ target_sources(nabto_webrtc_message_transport PUBLIC
2425
FILES
2526
include/nabto/webrtc/util/message_transport.hpp
2627
)
27-

sdk/src/signaling_util/message_transport/src/shared_secret_message_signer.hpp

Lines changed: 3 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,15 @@
11
#pragma once
22

33
#include "message_signer.hpp"
4-
#include <jwt-cpp/traits/nlohmann-json/defaults.h>
5-
6-
#include <nabto/webrtc/device.hpp>
7-
#include <nabto/webrtc/util/logging.hpp>
8-
#include <nabto/webrtc/util/uuid.hpp>
9-
10-
#include <nlohmann/json.hpp>
11-
12-
#include <memory>
134

145
namespace nabto {
156
namespace webrtc {
167
namespace util {
178

18-
class SharedSecretMessageSigner : public MessageSigner {
9+
class SharedSecretMessageSigner {
1910
public:
20-
static MessageSignerPtr create(std::string& secret, std::string& secretId) {
21-
auto sig = std::make_shared<SharedSecretMessageSigner>(secret, secretId);
22-
return sig;
23-
}
24-
25-
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
26-
SharedSecretMessageSigner(std::string& secret, std::string& secretId)
27-
: secret_(secret), secretId_(secretId) {
28-
myNonce_ = generate_uuid_v4();
29-
}
30-
31-
static std::string getKeyId(const nlohmann::json& message) {
32-
NPLOGD << "signaling signer handle msg" << message.dump();
33-
try {
34-
auto jwt = message.at("jwt").get<std::string>();
35-
auto decoded = jwt::decode<jwt::traits::nlohmann_json>(jwt);
36-
auto kidClaim = decoded.get_header_claim("kid");
37-
auto keyId = kidClaim.as_string();
38-
return keyId;
39-
} catch (std::exception& ex) {
40-
NPLOGE << "Failed to get key ID from JWT: " << ex.what();
41-
return "";
42-
}
43-
}
44-
45-
nlohmann::json signMessage(const nlohmann::json& msg) override {
46-
if (nextMessageSignSeq_ != 0 && remoteNonce_.empty()) {
47-
NPLOGE << "Tried to sign message with seq: " << nextMessageSignSeq_
48-
<< " and an empty remote nonce";
49-
throw std::runtime_error("Invalid State");
50-
}
51-
NPLOGD << "Signing message: " << msg.dump()
52-
<< " with seq: " << nextMessageSignSeq_
53-
<< " and remoteNonce: " << remoteNonce_;
54-
55-
const uint32_t seq = nextMessageSignSeq_;
56-
nextMessageSignSeq_++;
57-
58-
auto jwt = jwt::create<jwt::traits::nlohmann_json>()
59-
.set_payload_claim("message", msg)
60-
.set_payload_claim("messageSeq", seq)
61-
.set_payload_claim("signerNonce", myNonce_);
62-
63-
if (!secretId_.empty()) {
64-
jwt.set_key_id(secretId_);
65-
}
66-
67-
if (!remoteNonce_.empty()) {
68-
jwt.set_payload_claim("verifierNonce", remoteNonce_);
69-
}
70-
71-
auto token = jwt.sign(jwt::algorithm::hs256(secret_));
72-
73-
nlohmann::json message = {{"type", "JWT"}, {"jwt", token}};
74-
75-
return message;
76-
}
77-
78-
nlohmann::json verifyMessage(const nlohmann::json& msg) override {
79-
NPLOGD << "signaling signer handle msg" << msg.dump();
80-
try {
81-
auto jwt = msg.at("jwt").get<std::string>();
82-
auto decoded = jwt::decode(jwt);
83-
84-
// TODO(tk): handle optional key ID and find secret based on key ID if it
85-
// exists auto keyId = decoded.get_key_id();
86-
auto verifier =
87-
jwt::verify().allow_algorithm(jwt::algorithm::hs256(secret_));
88-
verifier.verify(decoded);
89-
const std::string& pl = decoded.get_payload();
90-
auto data = nlohmann::json::parse(pl);
91-
NPLOGD << "DATA: " << data.dump();
92-
const uint32_t claimedSeq = data.at("messageSeq").get<uint32_t>();
93-
if (claimedSeq != nextMessageVerifySeq_) {
94-
throw VerificationError();
95-
}
96-
const std::string signerNonce = data.at("signerNonce").get<std::string>();
97-
if (claimedSeq == 0) {
98-
remoteNonce_ = signerNonce;
99-
} else {
100-
if (signerNonce != remoteNonce_) {
101-
throw VerificationError();
102-
}
103-
const std::string verifyNonce =
104-
data.at("verifierNonce").get<std::string>();
105-
if (verifyNonce != myNonce_) {
106-
throw VerificationError();
107-
}
108-
}
109-
nextMessageVerifySeq_++;
110-
auto message = data.at("message");
111-
return message;
112-
} catch (std::exception& ex) {
113-
NPLOGE << "Failed to validate JWT: " << ex.what();
114-
throw VerificationError();
115-
}
116-
}
117-
118-
private:
119-
std::string secret_;
120-
std::string secretId_;
121-
122-
uint32_t nextMessageSignSeq_ = 0;
123-
uint32_t nextMessageVerifySeq_ = 0;
124-
std::string myNonce_;
125-
std::string remoteNonce_;
11+
static MessageSignerPtr create(const std::string& secret, const std::string& secretId);
12+
static std::string getKeyId(const nlohmann::json& message);
12613
};
12714

12815
} // namespace util
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#include "shared_secret_message_signer.hpp"
2+
3+
#include "message_signer.hpp"
4+
#include <jwt-cpp/traits/nlohmann-json/defaults.h>
5+
6+
#include <nabto/webrtc/device.hpp>
7+
#include <nabto/webrtc/util/logging.hpp>
8+
#include <nabto/webrtc/util/uuid.hpp>
9+
10+
#include <nlohmann/json.hpp>
11+
12+
#include <memory>
13+
14+
namespace nabto {
15+
namespace webrtc {
16+
namespace util {
17+
18+
class SharedSecretMessageSignerImpl : public MessageSigner {
19+
public:
20+
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
21+
SharedSecretMessageSignerImpl(const std::string& secret, const std::string& secretId)
22+
: secret_(secret), secretId_(secretId) {
23+
myNonce_ = generate_uuid_v4();
24+
}
25+
26+
static std::string getKeyId(const nlohmann::json& message) {
27+
NPLOGD << "signaling signer handle msg" << message.dump();
28+
try {
29+
auto jwt = message.at("jwt").get<std::string>();
30+
auto decoded = jwt::decode<jwt::traits::nlohmann_json>(jwt);
31+
auto kidClaim = decoded.get_header_claim("kid");
32+
auto keyId = kidClaim.as_string();
33+
return keyId;
34+
} catch (std::exception& ex) {
35+
NPLOGE << "Failed to get key ID from JWT: " << ex.what();
36+
return "";
37+
}
38+
}
39+
40+
nlohmann::json signMessage(const nlohmann::json& msg) override {
41+
if (nextMessageSignSeq_ != 0 && remoteNonce_.empty()) {
42+
NPLOGE << "Tried to sign message with seq: " << nextMessageSignSeq_
43+
<< " and an empty remote nonce";
44+
throw std::runtime_error("Invalid State");
45+
}
46+
NPLOGD << "Signing message: " << msg.dump()
47+
<< " with seq: " << nextMessageSignSeq_
48+
<< " and remoteNonce: " << remoteNonce_;
49+
50+
const uint32_t seq = nextMessageSignSeq_;
51+
nextMessageSignSeq_++;
52+
53+
auto jwt = jwt::create<jwt::traits::nlohmann_json>()
54+
.set_payload_claim("message", msg)
55+
.set_payload_claim("messageSeq", seq)
56+
.set_payload_claim("signerNonce", myNonce_);
57+
58+
if (!secretId_.empty()) {
59+
jwt.set_key_id(secretId_);
60+
}
61+
62+
if (!remoteNonce_.empty()) {
63+
jwt.set_payload_claim("verifierNonce", remoteNonce_);
64+
}
65+
66+
auto token = jwt.sign(jwt::algorithm::hs256(secret_));
67+
68+
nlohmann::json message = {{"type", "JWT"}, {"jwt", token}};
69+
70+
return message;
71+
}
72+
73+
nlohmann::json verifyMessage(const nlohmann::json& msg) override {
74+
NPLOGD << "signaling signer handle msg" << msg.dump();
75+
try {
76+
auto jwt = msg.at("jwt").get<std::string>();
77+
auto decoded = jwt::decode(jwt);
78+
79+
// TODO(tk): handle optional key ID and find secret based on key ID if it
80+
// exists auto keyId = decoded.get_key_id();
81+
auto verifier =
82+
jwt::verify().allow_algorithm(jwt::algorithm::hs256(secret_));
83+
verifier.verify(decoded);
84+
const std::string& pl = decoded.get_payload();
85+
auto data = nlohmann::json::parse(pl);
86+
NPLOGD << "DATA: " << data.dump();
87+
const uint32_t claimedSeq = data.at("messageSeq").get<uint32_t>();
88+
if (claimedSeq != nextMessageVerifySeq_) {
89+
throw VerificationError();
90+
}
91+
const std::string signerNonce = data.at("signerNonce").get<std::string>();
92+
if (claimedSeq == 0) {
93+
remoteNonce_ = signerNonce;
94+
} else {
95+
if (signerNonce != remoteNonce_) {
96+
throw VerificationError();
97+
}
98+
const std::string verifyNonce =
99+
data.at("verifierNonce").get<std::string>();
100+
if (verifyNonce != myNonce_) {
101+
throw VerificationError();
102+
}
103+
}
104+
nextMessageVerifySeq_++;
105+
auto message = data.at("message");
106+
return message;
107+
} catch (std::exception& ex) {
108+
NPLOGE << "Failed to validate JWT: " << ex.what();
109+
throw VerificationError();
110+
}
111+
}
112+
113+
private:
114+
std::string secret_;
115+
std::string secretId_;
116+
117+
uint32_t nextMessageSignSeq_ = 0;
118+
uint32_t nextMessageVerifySeq_ = 0;
119+
std::string myNonce_;
120+
std::string remoteNonce_;
121+
};
122+
123+
MessageSignerPtr SharedSecretMessageSigner::create(const std::string& secret, const std::string& secretId) {
124+
auto sig = std::make_shared<SharedSecretMessageSignerImpl>(secret, secretId);
125+
return sig;
126+
}
127+
128+
std::string SharedSecretMessageSigner::getKeyId(const nlohmann::json& message) {
129+
return SharedSecretMessageSignerImpl::getKeyId(message);
130+
}
131+
132+
} // namespace util
133+
} // namespace webrtc
134+
} // namespace nabto

0 commit comments

Comments
 (0)