Skip to content

v4.1.0

Choose a tag to compare

@paolostivanin paolostivanin released this 29 Apr 13:06
c2bab8c

Highlights

  • otpauth:// URI parser and builder — full round-trip support for the de-facto Google Authenticator URI format used by most TOTP/HOTP apps and QR provisioning flows.
  • Context API — bundle digits, period, and algo once with cotp_ctx_create, then call cotp_ctx_totp / _hotp / _steam_totp etc. without repeating the parameters. Contexts are immutable and safe to share across threads.
  • cotp_strerror — static, never-NULL human-readable description for any cotp_error_t value.
  • Public secure utilitiescotp_secure_memzero (compiler-elision-proof zeroing) and cotp_timing_safe_memcmp (constant-time compare) are now part of the public API, so callers can scrub their own secret buffers and compare secret-derived tokens with the same primitives the library uses internally.

New APIs

const char *cotp_strerror(cotp_error_t err);

void cotp_secure_memzero(void *ptr, size_t len);
int  cotp_timing_safe_memcmp(const void *a, const void *b, size_t len);

cotp_ctx *cotp_ctx_create(int digits, int period, int sha_algo);
void      cotp_ctx_free(cotp_ctx *ctx);
char     *cotp_ctx_totp(cotp_ctx *ctx, const char *base32_secret, cotp_error_t *err);
char     *cotp_ctx_totp_at(cotp_ctx *ctx, const char *base32_secret, long timestamp, cotp_error_t *err);
char     *cotp_ctx_hotp(cotp_ctx *ctx, const char *base32_secret, long counter, cotp_error_t *err);
char     *cotp_ctx_steam_totp(cotp_ctx *ctx, const char *base32_secret, cotp_error_t *err);
char     *cotp_ctx_steam_totp_at(cotp_ctx *ctx, const char *base32_secret, long timestamp, cotp_error_t *err);
#ifdef COTP_ENABLE_VALIDATION
int       cotp_ctx_validate_totp(cotp_ctx *ctx, const char *user_code, const char *base32_secret,
                                 long timestamp, int window, int *matched_delta, cotp_error_t *err);
#endif

cotp_otpauth_uri *cotp_otpauth_uri_parse(const char *uri, cotp_error_t *err);
char             *cotp_otpauth_uri_build(const cotp_otpauth_uri *u, cotp_error_t *err);
void              cotp_otpauth_uri_free(cotp_otpauth_uri *u);

Hardening

  • HMAC errors are now propagated across all three backends (gcrypt, OpenSSL, MbedTLS). Previously some backend failure paths could silently produce invalid output.
  • Base32 decoder rejects malformed padding counts (2, 5, 7, >6) and data characters following padding, per RFC 4648.
  • validate_totp_in_window is overflow-safe: window is clamped to ±1024 periods, time arithmetic uses __builtin_*_overflow, INT_MIN is handled, and the comparison is constant-time.
  • otpauth:// URI parser rejects %00 payloads (which previously caused silent NUL truncation of secrets).
  • COTP_WUR (warn-unused-result) annotation applied to every return-value-bearing public function.

Build / Test / CI

  • libFuzzer harnesses for base32_decode, get_totp_at, and the otpauth:// parser. Opt in with -DCOTP_BUILD_FUZZERS=ON (requires Clang).
  • ASan + UBSan CI workflow runs the full test suite across all three backends on every push and PR.
  • Fuzz-smoke CI workflow runs each fuzzer for 30 seconds on every push and PR.
  • CMake asserts that COTP_VERSION_STRING and the project version stay in sync.
  • Cross-platform linker hardening flags via the CMake LINKER: syntax (fixes macOS).

Compatibility

ABI-compatible with v4.0.x — SOVERSION stays at 4. New symbols are purely additive. You can drop the new .so in place of the old; recompilation is only needed if you want to use the new APIs.

Documentation

The README has been substantially expanded: Quick Index near the top; end-to-end examples for the Context, Validation, otpauth, and Base32 APIs; a Utilities section; an expanded Operational Notes section (system clock, HOTP counter persistence, Steam secret format, minimum secret length, thread safety, scrubbing); and explicit notes on Base32 lenient-mode behavior.

Full changelog

v4.0.1...v4.1.0


sha256: e51016eb220647e7f16b67c0baae2a42730b07fec3131aaad0f39a3a2a638b89