File: //opt/getbackup/bin/gblic_verify.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
static const char *PUBKEY_PEM =
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmCYQUr7+iWlvR2FbFOqK\n"
"PtvUQcSh47Hoh4XdKKTQDYt0HM/0AK5RrH6ymfNaXl/D+Py47vgMUDOjMu8R8QV7\n"
"sYXmRBgfcr6x1C2RpX0BKtYQRF7PAeJfmVh3VNF1rRq9zEN7Yvz7qzOHNlfSYtsz\n"
"1KpRIfX+sttA62DKvin+3X9bLz9C4rVAHDpIyLMAyPW5nKoCPPtsfj3sHhv56SYF\n"
"BeQ5BIKinz8CxJBmQ492EwgnQCyfYOPMOWQ7i+n+nVf3WFCYrDqPLzD1TO/7MyNW\n"
"HT+c/WKQE+6wiTE6aUqH/QiX5b99LjBMF65IcK+8Tkd+uZ0K18iGDxsrjbxSI859\n"
"AQIDAQAB\n"
"-----END PUBLIC KEY-----\n";
static const char *argval(int argc, char **argv, const char *name) {
for (int i = 1; i < argc - 1; ++i) {
if (strcmp(argv[i], name) == 0) return argv[i + 1];
}
return NULL;
}
static int decode_b64(const char *in, unsigned char **out, size_t *outlen) {
if (!in || !*in) return 0;
size_t len = strlen(in);
char *tmp = (char *)malloc(len + 1);
if (!tmp) return 0;
size_t j = 0;
for (size_t i = 0; i < len; ++i) {
if (!isspace((unsigned char)in[i])) tmp[j++] = in[i];
}
tmp[j] = '\0';
size_t alloc = (j * 3) / 4 + 4;
unsigned char *buf = (unsigned char *)malloc(alloc);
if (!buf) { free(tmp); return 0; }
int n = EVP_DecodeBlock(buf, (const unsigned char *)tmp, (int)j);
if (n <= 0) { free(tmp); free(buf); return 0; }
int pad = 0;
if (j >= 1 && tmp[j - 1] == '=') pad++;
if (j >= 2 && tmp[j - 2] == '=') pad++;
n -= pad;
free(tmp);
if (n <= 0) { free(buf); return 0; }
*out = buf;
*outlen = (size_t)n;
return 1;
}
int main(int argc, char **argv) {
const char *status = argval(argc, argv, "--status");
const char *expires = argval(argc, argv, "--expires");
const char *customer = argval(argc, argv, "--customer");
const char *ts_s = argval(argc, argv, "--ts");
const char *sig_b64 = argval(argc, argv, "--sig-b64");
const char *expected_nonce = argval(argc, argv, "--expected-nonce");
const char *resp_nonce = argval(argc, argv, "--resp-nonce");
const char *now_s = argval(argc, argv, "--now");
const char *skew_s = argval(argc, argv, "--max-skew");
const char *allow_legacy_s = argval(argc, argv, "--allow-legacy");
if (!status || !ts_s || !sig_b64) return 2;
int allow_legacy = (allow_legacy_s && atoi(allow_legacy_s) == 1) ? 1 : 0;
int has_expected_nonce = (expected_nonce && *expected_nonce) ? 1 : 0;
int has_resp_nonce = (resp_nonce && *resp_nonce) ? 1 : 0;
int use_nonce = has_expected_nonce && has_resp_nonce;
if (use_nonce && strcmp(expected_nonce, resp_nonce) != 0) return 3;
if (!use_nonce && !allow_legacy) return 11;
long long ts = atoll(ts_s);
long long now = now_s ? atoll(now_s) : (long long)time(NULL);
long long max_skew = skew_s ? atoll(skew_s) : 600;
if (ts <= 0 || llabs(now - ts) > max_skew) return 4;
if (!expires) expires = "";
if (!customer) customer = "";
size_t pay_len = strlen(status) + strlen(expires) + strlen(customer) + strlen(ts_s) + 8;
if (use_nonce) pay_len += strlen(resp_nonce) + 1;
char *payload = (char *)malloc(pay_len + 1);
if (!payload) return 5;
if (use_nonce) {
snprintf(payload, pay_len + 1, "%s\n%s\n%s\n%s\n%s", status, expires, customer, ts_s, resp_nonce);
} else {
snprintf(payload, pay_len + 1, "%s\n%s\n%s\n%s", status, expires, customer, ts_s);
}
unsigned char *sig = NULL;
size_t sig_len = 0;
if (!decode_b64(sig_b64, &sig, &sig_len)) { free(payload); return 6; }
BIO *bio = BIO_new_mem_buf((void *)PUBKEY_PEM, -1);
if (!bio) { free(payload); free(sig); return 7; }
EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!pkey) { free(payload); free(sig); return 8; }
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) { EVP_PKEY_free(pkey); free(payload); free(sig); return 9; }
int ok = 0;
if (EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, pkey) == 1 &&
EVP_DigestVerifyUpdate(ctx, payload, strlen(payload)) == 1) {
ok = EVP_DigestVerifyFinal(ctx, sig, sig_len) == 1;
}
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(pkey);
free(payload);
free(sig);
return ok ? 0 : 10;
}