C ++, Google, ServiceAccount, OAUTH2_JWT -> SHA256withRSA -> «error_description»: «Недопустимая подпись JWT». - PullRequest
0 голосов
/ 14 апреля 2020

Получил "Недопустимая подпись JWT". Кажется, что только подписание неправильно. Но я просто не знаю, что делать. Пожалуйста, помогите!

Curl работает на 100% Base64 вроде работает нормально. Декодеры заголовка и утверждения в порядке.

Здесь есть некоторая информация здесь (REST), если это поможет.

bool RSASign( RSA* rsa, const unsigned char* Msg, size_t MsgLen, unsigned char** EncMsg, size_t* MsgLenEnc) 
{
  EVP_MD_CTX* m_RSASignCtx = EVP_MD_CTX_create();
  EVP_PKEY* priKey  = EVP_PKEY_new();
  EVP_PKEY_assign_RSA(priKey, rsa);
  if (EVP_DigestSignInit(m_RSASignCtx,NULL, EVP_sha256(), NULL,priKey)<=0) { std::cout << "BAD! " << std::endl; return false; }
  if (EVP_DigestSignUpdate(m_RSASignCtx, Msg, MsgLen) <= 0) { std::cout << "BAD! " << std::endl; return false; }
  if (EVP_DigestSignFinal(m_RSASignCtx, NULL, MsgLenEnc) <=0) { std::cout << "BAD! " << std::endl; return false; }
  *EncMsg = (unsigned char*)malloc(*MsgLenEnc);
  if (EVP_DigestSignFinal(m_RSASignCtx, *EncMsg, MsgLenEnc) <= 0) { std::cout << "BAD! " << std::endl; return false; }

  EVP_MD_CTX_free(m_RSASignCtx);
  return true;
}

    // JWT HEADER
    std::string jwtHeader = base64_encode( "{\"alg\":\"RS256\",\"typ\":\"JWT\"}" );

    // JWT CLAIM
    std::string jwtClaim = base64_encode( ... );

    // JWT SIGNATURE
    std::string JWS  = jwtHeader + "." + jwtClaim;
    const char* privateKey = "-----BEGIN PRIVATE KEY-----\n...";

    // HASH        
        SHA256_CTX sha_ctx = { 0 };
        unsigned char digest[SHA256_DIGEST_LENGTH];
        SHA256_Init(&sha_ctx);
        SHA256_Update(&sha_ctx, JWS.c_str(), JWS.size());
        SHA256_Final(digest, &sha_ctx);

    // SIGN
    FILE *file = nullptr;
    file = fopen("file.key", "r");
    if (!file) { std::cout << "BAD FILE" << std::endl; }
    RSA* rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
    fclose(file);

    if(!rsa)
       std::cout << "BAD KEY" << std::endl;

    // there is no luck with or without sha256 before signing 
    if (RSASign( rsa, (const unsigned char*) JWS.c_str(), JWS.length(), &sig, (size_t*)&slen))
            std::cout << "SIGNED size: " << slen << std::endl;

        // TOKEN REQUEST
        std::string sign = base64_encode(sig, slen);
        std::string requestStr = "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=" + JWS + "." + sign;

        headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
        curl_easy_setopt(curl_handle, CURLOPT_URL, "https://oauth2.googleapis.com/token");
        curl_easy_setopt( ... CURLOPT_POST, CURLOPT_HTTPHEADER, CURLOPT_POSTFIELDS ... );

ОБНОВЛЕНИЕ:

ОК , Теперь я знаю, что мне нужен SHA256 с RSA. Но проблема все еще там.

Ответы [ 2 ]

1 голос
/ 14 апреля 2020

Спасибо, Ботье! Большое спасибо за попытку помочь мне. Но у меня больше нет времени на изучение openssl. Итак, я нашел отличный: https://github.com/Thalhammer/jwt-cpp отсюда jwt.io

Он не поддерживает поле 'scope' для утверждение jwt, поэтому я просто добавил метод в класс в заголовок: 'set_scope (...);'.

Десять, 10 ... Нееет, Вы просто не можете чувствовать мою боль из-за openssl_from_devs_with_crooked_hands_with_no_human_docs. 10 строк кода и готово!

Он имеет простые источники, поэтому вы можете узнать, как работать с ssl оттуда. Если вы хотите использовать OpenSSL lib и не знаете, как она работает - подумайте дважды , возможно, это худший выбор в вашей жизни. Удачи!

0 голосов
/ 15 апреля 2020

Нет необходимости помечать этот ответ как принятый, ваш - безусловно, более простое решение. Я выкладываю это для будущих читателей, чтобы найти.

Для чего я смог воспроизвести необработанный ха sh в тестовом примере RS256 со следующим:

void die() {
    for (int err = ERR_get_error(); err != 0; err = ERR_get_error()) {
        fprintf(stderr, "%s\n", ERR_error_string(err, nullptr));
    }
    exit(1);
}

int main() {
    /* md is a SHA-256 digest in this example. */
    BIO *pem_BIO = BIO_new_mem_buf(RSA_pem, sizeof(RSA_pem));
    EVP_PKEY *signing_key = PEM_read_bio_PrivateKey(pem_BIO, nullptr, nullptr, nullptr);

    const unsigned char header_payload[] = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9";

    EVP_MD_CTX * MD_ctx = EVP_MD_CTX_new();
    bool success = true;
    success = EVP_DigestSignInit(MD_ctx, nullptr, EVP_get_digestbyname(SN_sha256WithRSAEncryption), nullptr, signing_key);
    if (!success) die();

    unsigned char sigbuf[512];
    size_t siglen = sizeof(sigbuf);
    success = EVP_DigestSign(MD_ctx, sigbuf, &siglen, header_payload, sizeof(header_payload)-1);
    if (!success) die();
    fwrite(sigbuf, 1, siglen, stdout);
}

Однако конечный результат все еще должен быть закодирован в base64 (с алфавитом, безопасным для URL).

...