summaryrefslogtreecommitdiff
path: root/src/common/cryptohash_openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/cryptohash_openssl.c')
-rw-r--r--src/common/cryptohash_openssl.c93
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");
+}