in azure-protected-vm-secrets/JsonWebToken.cpp [112:252]
void JsonWebToken::ParseToken(std::string const&token, bool verify)
{
std::vector<unsigned char> tokenVector(token.begin(), token.end());
std::string headerBase64 = "";
std::string payloadBase64 = "";
std::string signatureBase64 = "";
std::string header = "";
std::string payload = "";
std::string signature = "";
size_t first = std::string::npos;
size_t last = std::string::npos;
if (tokenVector.size() < 2) {
throw JwtError("Invalid JWT token.");
}
first = token.find_first_of('.');
last = token.find_last_of('.');
if (first == std::string::npos || last == std::string::npos || first == last) {
throw JwtError("Invalid JWT token.");
}
headerBase64 = std::string(tokenVector.begin(), tokenVector.begin() + first);
first++;
payloadBase64 = std::string(tokenVector.begin() + first, tokenVector.begin() + last);
last++;
signatureBase64 = std::string(tokenVector.begin() + last, tokenVector.end());
if (!headerBase64.empty()) {
try {
std::vector<unsigned char> headerVector = encoders::base64_url_decode(headerBase64);
header = std::string(headerVector.begin(), headerVector.end());
this->header = json::parse(header);
}
catch (json::parse_error& e) {
LIBSECRETS_LOG(LogLevel::Error, "Json Parse Error\n",
"Error message %s\n", e.what());
throw JwtError(e.what());
}
catch (...) {
LIBSECRETS_LOG(LogLevel::Error, "Json Parse Error\n",
"Generic Parsing Error\n");
throw JwtError("Failed to parse header.");
}
}
if (!payloadBase64.empty()) {
std::vector<unsigned char> payloadVector = encoders::base64_url_decode(payloadBase64);
payload = std::string(payloadVector.begin(), payloadVector.end());
try {
this->jwt = json::parse(payload);
if (this->jwt["exp"].is_number() && this->jwt["iat"].is_number()) {
// Check if the token is expired or not yet valid
// In Azure, the token expiration is set to 30 minutes after
// the token is issued & signed.
/*time_t exp = this->jwt["exp"];
time_t iat = this->jwt["iat"];
time_t now = time(0);
if (now > exp) {
// ParseError, Jwt subclass, timeError
throw JwtError("Token has expired.",
ErrorCode::ParsingError_Jwt_timeError);
}
if (now < iat) {
// ParseError, Jwt subclass, timeError
throw JwtError("Token is not yet valid.",
ErrorCode::ParsingError_Jwt_timeError);
}*/
}
}
catch (json::parse_error& e) {
LIBSECRETS_LOG(LogLevel::Error, "Json Parse Error\n",
"Error message %s\n", e.what());
throw JwtError(e.what());
}
catch (...) {
LIBSECRETS_LOG(LogLevel::Error, "Json Parse Error\n",
"Generic Parsing Error\n");
throw JwtError("Failed to parse payload.");
}
}
if (!signatureBase64.empty()) {
this->signature = encoders::base64_url_decode(signatureBase64);
if (verify) {
std::string signed_portion = token.substr(0, token.find_last_of('.'));
#ifndef PLATFORM_UNIX
std::unique_ptr<WincryptX509> x509 = std::make_unique<WincryptX509>();
#else
std::unique_ptr<OsslX509> x509 = std::make_unique<OsslX509>();
#endif
try {
std::for_each(std::begin(INTERMEDIATE_CERTS), std::end(INTERMEDIATE_CERTS),
[&](const auto cert) { x509->LoadIntermediateCertificate(cert); } );
x509->LoadLeafCertificate(std::string(this->header["x5c"]).c_str());
if (!x509->VerifyCertChain()) {
throw JwtError("Failed to verify certificate chain.");
}
else {
LIBSECRETS_LOG(
LogLevel::Debug, "Successfully Verified Certificate chain\n", "");
}
std::vector<unsigned char> signed_data(signed_portion.begin(), signed_portion.end());
if (!x509->VerifySignature(signed_data, this->signature)) {
throw JwtError("Failed to verify certificate chain.");
}
else {
LIBSECRETS_LOG(
LogLevel::Debug, "Successfully Verified Signature\n", "");
}
}
catch (json::out_of_range& e) {
// No x5c header
LIBSECRETS_LOG(LogLevel::Error, "Json Parse Error\n",
"Error message %s\n", e.what());
throw JwtError(e.what());
}
#ifndef PLATFORM_UNIX
catch (WinCryptError& e) {
// Certificate chain verification failed
LIBSECRETS_LOG(LogLevel::Error, "WinCrypt Error\n",
"Error message %s\n", e.what());
throw JwtError(e.what());
}
catch (BcryptError &e) {
// Signature verification failed
LIBSECRETS_LOG(LogLevel::Error, "Bcrypt Verification\n",
"Bcrypt status 0x%x occurred\n Message %s\t Bcrypt Info%s",
e.getStatusCode(), e.what(), e.getErrorInfo());
throw JwtError(e.getErrorInfo());
}
#else
catch (OsslError& e) {
// Certificate chain verification failed
LIBSECRETS_LOG(LogLevel::Error, "Openssl Error\n",
"Error message %s\n", e.what());
throw JwtError(e.what());
}
#endif
}
}
else {
LIBSECRETS_LOG(LogLevel::Debug, "JWT Information\n",
"No signature found in token\n");
}
}