Skip to content

Instantly share code, notes, and snippets.

@niuk
Created April 15, 2021 22:38
Show Gist options
  • Save niuk/6365b819a86a7e0b92d82328fcf87da5 to your computer and use it in GitHub Desktop.
Save niuk/6365b819a86a7e0b92d82328fcf87da5 to your computer and use it in GitHub Desktop.
Google OAuth JWT in C++
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "httplib.h"
char get_base64_char(char byte) {
if (byte < 26) {
return 'A' + byte;
} else if (byte < 52) {
return 'a' + byte - 26;
} else if (byte < 62) {
return '0' + byte - 52;
} else if (byte == 62) {
return '-';
} else if (byte == 63) {
return '_';
} else {
fprintf(stderr, "BAD BYTE: %02x\n", byte);
exit(1);
return 0;
}
}
// To execute C, please define "int main()"
void base64encode(char *output, const char *input, size_t input_length) {
size_t input_index = 0;
size_t output_index = 0;
for (; input_index < input_length; ++output_index) {
switch (output_index % 4) {
case 0:
output[output_index] = get_base64_char((0xfc & input[input_index]) >> 2);
break;
case 1:
output[output_index] = get_base64_char(((0x03 & input[input_index]) << 4) | ((0xf0 & input[input_index + 1]) >> 4));
++input_index;
break;
case 2:
output[output_index] = get_base64_char(((0x0f & input[input_index]) << 2) | ((0xc0 & input[input_index + 1]) >> 6));
++input_index;
break;
case 3:
output[output_index] = get_base64_char(0x3f & input[input_index]);
++input_index;
break;
default:
exit(1);
}
}
output[output_index] = '\0';
}
int main(int argc, char **argv) {
const char *header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
const int iat = time(NULL);
const int exp = iat + 60 * 60 - 1;
char claim_set[1024];
sprintf(claim_set, "{\
\"iss\":\"%s\",\
\"scope\":\"%s\",\
\"aud\":\"https://oauth2.googleapis.com/token\",\
\"exp\":%d,\
\"iat\":%d\
}", argv[1], argv[2], argc > 3 ? atoi(argv[3]) : exp, argc > 4 ? atoi(argv[4]) : iat);
printf("%s\n", claim_set);
char header_64[1024];
base64encode(header_64, header, strlen(header));
char claim_set_64[1024];
base64encode(claim_set_64, claim_set, strlen(claim_set));
char input[1024];
int input_length = sprintf(input, "%s.%s", header_64, claim_set_64);
printf("input = %s\ninput_length = %d\n", input, input_length);
unsigned char *digest = SHA256((const unsigned char *)input, input_length, NULL);
char digest_str[1024];
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
sprintf(digest_str + i * 2, "%02x", digest[i]);
}
digest_str[SHA256_DIGEST_LENGTH * 2] = '\0';
printf("digest_str = %s\n", digest_str);
FILE *key_file = fopen("key.pem", "r");
RSA *rsa = PEM_read_RSAPrivateKey(key_file, NULL, NULL, NULL);
int rsa_size = RSA_size(rsa);
printf("rsa_size = %d\n", rsa_size);
if (rsa != NULL) {
unsigned char sigret[rsa_size];
unsigned int siglen;
if (RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, sigret, &siglen, rsa)) {
printf("siglen = %d\n", siglen);
if (RSA_verify(NID_sha256, digest, SHA256_DIGEST_LENGTH, sigret, siglen, rsa)) {
char signature_64[1024];
base64encode(signature_64, (const char *)sigret, siglen);
char jwt[1024];
sprintf(jwt, "%s.%s", input, signature_64);
printf("jwt = %s\n", jwt);
httplib::Client cli("https://oauth2.googleapis.com");
httplib::Params params;
params.emplace("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
params.emplace("assertion", jwt);
auto result = cli.Post("/token", params);
printf("status = %d\nbody = %s\n", result->status, result->body.c_str());
} else {
printf("Could not verify RSA signature.");
}
} else {
unsigned long err = ERR_get_error();
printf("RSA_sign failed: %lu, %s\n", err, ERR_error_string(err, NULL));
}
RSA_free(rsa);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment