void JsonWebToken::ParseToken()

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");
    }
}