openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.6 KiB

#include "tools/replay/api.h"
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <cassert>
#include <chrono>
#include <iostream>
#include "common/params.h"
#include "common/version.h"
#include "system/hardware/hw.h"
namespace CommaApi2 {
// Base64 URL-safe character set (uses '-' and '_' instead of '+' and '/')
static const std::string base64url_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_";
std::string base64url_encode(const std::string &in) {
std::string out;
int val = 0, valb = -6;
for (unsigned char c : in) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
out.push_back(base64url_chars[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6) {
out.push_back(base64url_chars[((val << 8) >> (valb + 8)) & 0x3F]);
}
return out;
}
EVP_PKEY *get_rsa_private_key() {
static std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> rsa_private(nullptr, EVP_PKEY_free);
if (!rsa_private) {
FILE *fp = fopen(Path::rsa_file().c_str(), "rb");
if (!fp) {
std::cerr << "No RSA private key found, please run manager.py or registration.py" << std::endl;
return nullptr;
}
rsa_private.reset(PEM_read_PrivateKey(fp, NULL, NULL, NULL));
fclose(fp);
}
return rsa_private.get();
}
std::string rsa_sign(const std::string &data) {
EVP_PKEY *private_key = get_rsa_private_key();
if (!private_key) return {};
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
assert(mdctx != nullptr);
std::vector<uint8_t> sig(EVP_PKEY_size(private_key));
uint32_t sig_len;
EVP_SignInit(mdctx, EVP_sha256());
EVP_SignUpdate(mdctx, data.data(), data.size());
int ret = EVP_SignFinal(mdctx, sig.data(), &sig_len, private_key);
EVP_MD_CTX_free(mdctx);
assert(ret == 1);
assert(sig.size() == sig_len);
return std::string(sig.begin(), sig.begin() + sig_len);
}
std::string create_jwt(const json11::Json &extra, int exp_time) {
int now = std::chrono::seconds(std::time(nullptr)).count();
std::string dongle_id = Params().get("DongleId");
// Create header and payload
json11::Json header = json11::Json::object{{"alg", "RS256"}};
auto payload = json11::Json::object{
{"identity", dongle_id},
{"iat", now},
{"nbf", now},
{"exp", now + exp_time},
};
// Merge extra payload
for (const auto &item : extra.object_items()) {
payload[item.first] = item.second;
}
// JWT construction
std::string jwt = base64url_encode(header.dump()) + '.' +
base64url_encode(json11::Json(payload).dump());
// Hash and sign
std::string hash(SHA256_DIGEST_LENGTH, '\0');
SHA256((uint8_t *)jwt.data(), jwt.size(), (uint8_t *)hash.data());
std::string signature = rsa_sign(hash);
return jwt + "." + base64url_encode(signature);
}
std::string create_token(bool use_jwt, const json11::Json &payloads, int expiry) {
if (use_jwt) {
return create_jwt(payloads, expiry);
}
std::string token_json = util::read_file(util::getenv("HOME") + "/.comma/auth.json");
std::string err;
auto json = json11::Json::parse(token_json, err);
if (!err.empty()) {
std::cerr << "Error parsing auth.json " << err << std::endl;
return "";
}
return json["access_token"].string_value();
}
std::string httpGet(const std::string &url, long *response_code) {
CURL *curl = curl_easy_init();
assert(curl);
std::string readBuffer;
const std::string token = CommaApi2::create_token(!Hardware::PC());
// Set up the lambda for the write callback
// The '+' makes the lambda non-capturing, allowing it to be used as a C function pointer
auto writeCallback = +[](char *contents, size_t size, size_t nmemb, std::string *userp) ->size_t{
size_t totalSize = size * nmemb;
userp->append((char *)contents, totalSize);
return totalSize;
};
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// Handle headers
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "User-Agent: openpilot-" COMMA_VERSION);
if (!token.empty()) {
headers = curl_slist_append(headers, ("Authorization: JWT " + token).c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
CURLcode res = curl_easy_perform(curl);
if (response_code) {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, response_code);
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return res == CURLE_OK ? readBuffer : std::string{};
}
} // namespace CommaApi