diff options
Diffstat (limited to 'src/common/cryptohash_openssl.c')
-rw-r--r-- | src/common/cryptohash_openssl.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c index f7b390ed54..2e835b066b 100644 --- a/src/common/cryptohash_openssl.c +++ b/src/common/cryptohash_openssl.c @@ -21,6 +21,7 @@ #include "postgres_fe.h" #endif +#include <openssl/err.h> #include <openssl/evp.h> #include "common/cryptohash.h" @@ -46,6 +47,14 @@ #define FREE(ptr) free(ptr) #endif +/* Set of error states */ +typedef enum pg_cryptohash_errno +{ + PG_CRYPTOHASH_ERROR_NONE = 0, + PG_CRYPTOHASH_ERROR_DEST_LEN, + PG_CRYPTOHASH_ERROR_OPENSSL +} pg_cryptohash_errno; + /* * Internal pg_cryptohash_ctx structure. * @@ -55,6 +64,8 @@ struct pg_cryptohash_ctx { pg_cryptohash_type type; + pg_cryptohash_errno error; + const char *errreason; EVP_MD_CTX *evpctx; @@ -63,6 +74,19 @@ struct pg_cryptohash_ctx #endif }; +static const char * +SSLerrmessage(unsigned long ecode) +{ + if (ecode == 0) + return NULL; + + /* + * This may return NULL, but we would fall back to a default error path if + * that were the case. + */ + return ERR_reason_error_string(ecode); +} + /* * pg_cryptohash_create * @@ -88,6 +112,8 @@ pg_cryptohash_create(pg_cryptohash_type type) return NULL; memset(ctx, 0, sizeof(pg_cryptohash_ctx)); ctx->type = type; + ctx->error = PG_CRYPTOHASH_ERROR_NONE; + ctx->errreason = NULL; /* * Initialization takes care of assigning the correct type for OpenSSL. @@ -153,7 +179,11 @@ pg_cryptohash_init(pg_cryptohash_ctx *ctx) /* OpenSSL internals return 1 on success, 0 on failure */ if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL; return -1; + } return 0; } @@ -174,7 +204,11 @@ pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) /* OpenSSL internals return 1 on success, 0 on failure */ if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL; return -1; + } return 0; } @@ -195,27 +229,45 @@ pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len) { case PG_MD5: if (len < MD5_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; return -1; + } break; case PG_SHA1: if (len < SHA1_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; return -1; + } break; case PG_SHA224: if (len < PG_SHA224_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; return -1; + } break; case PG_SHA256: if (len < PG_SHA256_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; return -1; + } break; case PG_SHA384: if (len < PG_SHA384_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; return -1; + } break; case PG_SHA512: if (len < PG_SHA512_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; return -1; + } break; } @@ -223,7 +275,11 @@ pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len) /* OpenSSL internals return 1 on success, 0 on failure */ if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL; return -1; + } return 0; } @@ -248,3 +304,40 @@ pg_cryptohash_free(pg_cryptohash_ctx *ctx) explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); FREE(ctx); } + +/* + * pg_cryptohash_error + * + * Returns a static string providing errors about an error that + * happened during a computation. + */ +const char * +pg_cryptohash_error(pg_cryptohash_ctx *ctx) +{ + /* + * This implementation would never fail because of an out-of-memory error, + * except when creating the context. + */ + if (ctx == NULL) + return _("out of memory"); + + /* + * If a reason is provided, rely on it, else fallback to any error code + * set. + */ + if (ctx->errreason) + return ctx->errreason; + + switch (ctx->error) + { + case PG_CRYPTOHASH_ERROR_NONE: + return _("success"); + case PG_CRYPTOHASH_ERROR_DEST_LEN: + return _("destination buffer too small"); + case PG_CRYPTOHASH_ERROR_OPENSSL: + return _("OpenSSL failure"); + } + + Assert(false); /* cannot be reached */ + return _("success"); +} |