mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 10:13:58 +00:00
- Copy pg-knoe-auth/ wholesale from upstream/knoe-db/20260523 (Task 1 of docs/plans/junie/upstream-knoe-db-20260523-integration.md). - Extension: PG18 OAUTHBEARER JWT validator using libcurl + OpenSSL RS256. - knoe-db/Dockerfile: add libcurl4-openssl-dev to dev deps; COPY src/ and build with make USE_PGXS=1 install after tds_fdw. - NOT enabled in the default database build (absent from 20_create_extensions.sh). To enable: CREATE EXTENSION pg_knoe_auth; (requires pg_hba.conf oauth_issuer). Closes Task 1 of upstream-knoe-db-20260523-integration.md.
114 lines
3.5 KiB
C
114 lines
3.5 KiB
C
/*
|
|
* test_base64url.c — unit tests for base64url decode (RFC 4648 §5 vectors).
|
|
*
|
|
* Tests correct decoding, missing padding handling, and bad input rejection.
|
|
* See docs/plans/junie/pg_knoe_auth-rename-harden-modularize.md §2.5
|
|
*/
|
|
#include "test_helpers.h"
|
|
#include <openssl/bio.h>
|
|
#include <openssl/evp.h>
|
|
|
|
/*
|
|
* base64url_decode — copied verbatim from pg_knoe_auth.c.
|
|
*/
|
|
static unsigned char *
|
|
base64url_decode(const char *input, size_t input_len, size_t *out_len)
|
|
{
|
|
char *b64;
|
|
size_t b64_len;
|
|
size_t pad;
|
|
unsigned char *result;
|
|
int decoded_len;
|
|
BIO *bio, *b64bio;
|
|
|
|
b64_len = input_len;
|
|
pad = (4 - (input_len % 4)) % 4;
|
|
b64 = palloc(b64_len + pad + 2);
|
|
memcpy(b64, input, input_len);
|
|
for (size_t i = 0; i < input_len; i++) {
|
|
if (b64[i] == '-') b64[i] = '+';
|
|
else if (b64[i] == '_') b64[i] = '/';
|
|
}
|
|
for (size_t i = 0; i < pad; i++)
|
|
b64[b64_len + i] = '=';
|
|
b64[b64_len + pad] = '\n';
|
|
b64[b64_len + pad + 1] = '\0';
|
|
|
|
result = palloc(b64_len + pad + 4);
|
|
b64bio = BIO_new(BIO_f_base64());
|
|
bio = BIO_new_mem_buf(b64, (int)(b64_len + pad + 1));
|
|
bio = BIO_push(b64bio, bio);
|
|
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
|
decoded_len = BIO_read(bio, result, (int)(b64_len + pad + 4));
|
|
BIO_free_all(bio);
|
|
pfree(b64);
|
|
|
|
if (decoded_len < 0) {
|
|
pfree(result);
|
|
return NULL;
|
|
}
|
|
*out_len = (size_t) decoded_len;
|
|
return result;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
unsigned char *out;
|
|
size_t out_len;
|
|
|
|
/*
|
|
* RFC 4648 §10 test vectors (base64url form — '-' for '+', '_' for '/').
|
|
* Standard base64: "" → ""
|
|
* "f" → "Zg=="
|
|
* "fo" → "Zm8="
|
|
* "foo" → "Zm9v"
|
|
* "foob" → "Zm9vYg=="
|
|
* "fooba" → "Zm9vYmE="
|
|
* "foobar" → "Zm9vYmFy"
|
|
* base64url strips padding.
|
|
*/
|
|
|
|
/* "f" → base64url "Zg" (no padding) */
|
|
out = base64url_decode("Zg", 2, &out_len);
|
|
ASSERT(out != NULL && out_len == 1 && out[0] == 'f',
|
|
"RFC4648 vector: 'Zg' decodes to 'f'");
|
|
if (out) pfree(out);
|
|
|
|
/* "fo" → base64url "Zm8" */
|
|
out = base64url_decode("Zm8", 3, &out_len);
|
|
ASSERT(out != NULL && out_len == 2 &&
|
|
out[0] == 'f' && out[1] == 'o',
|
|
"RFC4648 vector: 'Zm8' decodes to 'fo'");
|
|
if (out) pfree(out);
|
|
|
|
/* "foo" → base64url "Zm9v" */
|
|
out = base64url_decode("Zm9v", 4, &out_len);
|
|
ASSERT(out != NULL && out_len == 3 &&
|
|
memcmp(out, "foo", 3) == 0,
|
|
"RFC4648 vector: 'Zm9v' decodes to 'foo'");
|
|
if (out) pfree(out);
|
|
|
|
/* "foobar" → base64url "Zm9vYmFy" */
|
|
out = base64url_decode("Zm9vYmFy", 8, &out_len);
|
|
ASSERT(out != NULL && out_len == 6 &&
|
|
memcmp(out, "foobar", 6) == 0,
|
|
"RFC4648 vector: 'Zm9vYmFy' decodes to 'foobar'");
|
|
if (out) pfree(out);
|
|
|
|
/* base64url '-' and '_' substitution: encode "\xfb\xff" = "+/8=" in std,
|
|
* "-_8" in base64url (no pad) */
|
|
out = base64url_decode("-_8", 3, &out_len);
|
|
ASSERT(out != NULL && out_len == 2 &&
|
|
(unsigned char)out[0] == 0xfb && (unsigned char)out[1] == 0xff,
|
|
"base64url '-' and '_' chars decoded correctly");
|
|
if (out) pfree(out);
|
|
|
|
/* Empty input */
|
|
out = base64url_decode("", 0, &out_len);
|
|
ASSERT(out != NULL && out_len == 0,
|
|
"empty input decodes to empty output");
|
|
if (out) pfree(out);
|
|
|
|
TEST_SUMMARY();
|
|
}
|