2007-04-21 19:26:18 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
2014-05-28 01:42:08 +02:00
|
|
|
* UUID generation functions using the BSD, E2FS or OSSP UUID library
|
2007-04-21 19:26:18 +02:00
|
|
|
*
|
2022-01-08 01:04:57 +01:00
|
|
|
* Copyright (c) 2007-2022, PostgreSQL Global Development Group
|
2007-04-21 19:26:18 +02:00
|
|
|
*
|
2014-05-28 01:42:08 +02:00
|
|
|
* Portions Copyright (c) 2009 Andrew Gierth
|
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* contrib/uuid-ossp/uuid-ossp.c
|
2007-04-21 19:26:18 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
2014-05-28 01:42:08 +02:00
|
|
|
|
2007-04-21 19:26:18 +02:00
|
|
|
#include "fmgr.h"
|
2020-12-10 04:49:43 +01:00
|
|
|
#include "common/cryptohash.h"
|
2021-01-23 03:33:04 +01:00
|
|
|
#include "common/sha1.h"
|
2017-10-02 00:36:14 +02:00
|
|
|
#include "port/pg_bswap.h"
|
2007-04-21 19:26:18 +02:00
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/uuid.h"
|
|
|
|
|
2007-10-23 23:38:16 +02:00
|
|
|
/*
|
2014-05-28 01:42:08 +02:00
|
|
|
* It's possible that there's more than one uuid.h header file present.
|
|
|
|
* We expect configure to set the HAVE_ symbol for only the one we want.
|
|
|
|
*
|
|
|
|
* BSD includes a uuid_hash() function that conflicts with the one in
|
|
|
|
* builtins.h; we #define it out of the way.
|
2007-10-23 23:38:16 +02:00
|
|
|
*/
|
2014-05-28 01:42:08 +02:00
|
|
|
#define uuid_hash bsd_uuid_hash
|
|
|
|
|
2016-12-22 17:19:04 +01:00
|
|
|
#if defined(HAVE_UUID_H)
|
2007-05-15 21:47:51 +02:00
|
|
|
#include <uuid.h>
|
2016-12-22 17:19:04 +01:00
|
|
|
#elif defined(HAVE_OSSP_UUID_H)
|
2014-05-28 01:42:08 +02:00
|
|
|
#include <ossp/uuid.h>
|
2016-12-22 17:19:04 +01:00
|
|
|
#elif defined(HAVE_UUID_UUID_H)
|
2014-05-28 01:42:08 +02:00
|
|
|
#include <uuid/uuid.h>
|
2016-12-22 17:19:04 +01:00
|
|
|
#else
|
|
|
|
#error "please use configure's --with-uuid switch to select a UUID library"
|
2014-05-28 01:42:08 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#undef uuid_hash
|
2007-04-21 19:26:18 +02:00
|
|
|
|
2014-05-28 01:42:08 +02:00
|
|
|
/* Check our UUID length against OSSP's; better both be 16 */
|
|
|
|
#if defined(HAVE_UUID_OSSP) && (UUID_LEN != UUID_LEN_BIN)
|
2007-04-21 19:26:18 +02:00
|
|
|
#error UUID length mismatch
|
|
|
|
#endif
|
|
|
|
|
2014-05-28 01:42:08 +02:00
|
|
|
/* Define some constants like OSSP's, to make the code more readable */
|
|
|
|
#ifndef HAVE_UUID_OSSP
|
|
|
|
#define UUID_MAKE_MC 0
|
|
|
|
#define UUID_MAKE_V1 1
|
|
|
|
#define UUID_MAKE_V2 2
|
|
|
|
#define UUID_MAKE_V3 3
|
|
|
|
#define UUID_MAKE_V4 4
|
|
|
|
#define UUID_MAKE_V5 5
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A DCE 1.1 compatible source representation of UUIDs, derived from
|
|
|
|
* the BSD implementation. BSD already has this; OSSP doesn't need it.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_UUID_E2FS
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
uint32_t time_low;
|
|
|
|
uint16_t time_mid;
|
|
|
|
uint16_t time_hi_and_version;
|
|
|
|
uint8_t clock_seq_hi_and_reserved;
|
|
|
|
uint8_t clock_seq_low;
|
|
|
|
uint8_t node[6];
|
|
|
|
} dce_uuid_t;
|
|
|
|
#else
|
|
|
|
#define dce_uuid_t uuid_t
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* If not OSSP, we need some endianness-manipulation macros */
|
|
|
|
#ifndef HAVE_UUID_OSSP
|
|
|
|
|
|
|
|
#define UUID_TO_NETWORK(uu) \
|
|
|
|
do { \
|
2017-10-02 00:36:14 +02:00
|
|
|
uu.time_low = pg_hton32(uu.time_low); \
|
|
|
|
uu.time_mid = pg_hton16(uu.time_mid); \
|
|
|
|
uu.time_hi_and_version = pg_hton16(uu.time_hi_and_version); \
|
2014-05-28 01:42:08 +02:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define UUID_TO_LOCAL(uu) \
|
|
|
|
do { \
|
2017-10-02 00:36:14 +02:00
|
|
|
uu.time_low = pg_ntoh32(uu.time_low); \
|
|
|
|
uu.time_mid = pg_ntoh16(uu.time_mid); \
|
|
|
|
uu.time_hi_and_version = pg_ntoh16(uu.time_hi_and_version); \
|
2014-05-28 01:42:08 +02:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define UUID_V3_OR_V5(uu, v) \
|
|
|
|
do { \
|
|
|
|
uu.time_hi_and_version &= 0x0FFF; \
|
|
|
|
uu.time_hi_and_version |= (v << 12); \
|
|
|
|
uu.clock_seq_hi_and_reserved &= 0x3F; \
|
|
|
|
uu.clock_seq_hi_and_reserved |= 0x80; \
|
|
|
|
} while(0)
|
|
|
|
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
#endif /* !HAVE_UUID_OSSP */
|
2014-05-28 01:42:08 +02:00
|
|
|
|
2007-04-21 19:26:18 +02:00
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_nil);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_ns_dns);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_ns_url);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_ns_oid);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_ns_x500);
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_generate_v1);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_generate_v1mc);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_generate_v3);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_generate_v4);
|
|
|
|
PG_FUNCTION_INFO_V1(uuid_generate_v5);
|
|
|
|
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
|
|
|
|
2007-12-31 04:55:50 +01:00
|
|
|
static void
|
|
|
|
pguuid_complain(uuid_rc_t rc)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
char *err = uuid_error(rc);
|
2007-12-31 04:55:50 +01:00
|
|
|
|
|
|
|
if (err != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
|
|
|
|
errmsg("OSSP uuid library failure: %s", err)));
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
|
|
|
|
errmsg("OSSP uuid library failure: error code %d", rc)));
|
|
|
|
}
|
2007-04-21 19:26:18 +02:00
|
|
|
|
2014-05-29 19:51:02 +02:00
|
|
|
/*
|
|
|
|
* We create a uuid_t object just once per session and re-use it for all
|
|
|
|
* operations in this module. OSSP UUID caches the system MAC address and
|
|
|
|
* other state in this object. Reusing the object has a number of benefits:
|
|
|
|
* saving the cycles needed to fetch the system MAC address over and over,
|
|
|
|
* reducing the amount of entropy we draw from /dev/urandom, and providing a
|
|
|
|
* positive guarantee that successive generated V1-style UUIDs don't collide.
|
|
|
|
* (On a machine fast enough to generate multiple UUIDs per microsecond,
|
|
|
|
* or whatever the system's wall-clock resolution is, we'd otherwise risk
|
|
|
|
* collisions whenever random initialization of the uuid_t's clock sequence
|
|
|
|
* value chanced to produce duplicates.)
|
|
|
|
*
|
|
|
|
* However: when we're doing V3 or V5 UUID creation, uuid_make needs two
|
|
|
|
* uuid_t objects, one holding the namespace UUID and one for the result.
|
|
|
|
* It's unspecified whether it's safe to use the same uuid_t for both cases,
|
|
|
|
* so let's cache a second uuid_t for use as the namespace holder object.
|
|
|
|
*/
|
|
|
|
static uuid_t *
|
|
|
|
get_cached_uuid_t(int which)
|
|
|
|
{
|
|
|
|
static uuid_t *cached_uuid[2] = {NULL, NULL};
|
|
|
|
|
|
|
|
if (cached_uuid[which] == NULL)
|
|
|
|
{
|
|
|
|
uuid_rc_t rc;
|
|
|
|
|
|
|
|
rc = uuid_create(&cached_uuid[which]);
|
|
|
|
if (rc != UUID_RC_OK)
|
|
|
|
{
|
|
|
|
cached_uuid[which] = NULL;
|
|
|
|
pguuid_complain(rc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cached_uuid[which];
|
|
|
|
}
|
|
|
|
|
2007-04-21 19:26:18 +02:00
|
|
|
static char *
|
2009-06-11 16:49:15 +02:00
|
|
|
uuid_to_string(const uuid_t *uuid)
|
2007-04-21 19:26:18 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
char *buf = palloc(UUID_LEN_STR + 1);
|
|
|
|
void *ptr = buf;
|
|
|
|
size_t len = UUID_LEN_STR + 1;
|
2007-12-31 04:55:50 +01:00
|
|
|
uuid_rc_t rc;
|
2007-04-21 19:26:18 +02:00
|
|
|
|
2007-12-31 04:55:50 +01:00
|
|
|
rc = uuid_export(uuid, UUID_FMT_STR, &ptr, &len);
|
|
|
|
if (rc != UUID_RC_OK)
|
|
|
|
pguuid_complain(rc);
|
2007-04-21 19:26:18 +02:00
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2009-06-11 16:49:15 +02:00
|
|
|
string_to_uuid(const char *str, uuid_t *uuid)
|
2007-04-21 19:26:18 +02:00
|
|
|
{
|
2007-12-31 04:55:50 +01:00
|
|
|
uuid_rc_t rc;
|
|
|
|
|
|
|
|
rc = uuid_import(uuid, UUID_FMT_STR, str, UUID_LEN_STR + 1);
|
|
|
|
if (rc != UUID_RC_OK)
|
|
|
|
pguuid_complain(rc);
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Datum
|
|
|
|
special_uuid_value(const char *name)
|
|
|
|
{
|
2014-05-29 19:51:02 +02:00
|
|
|
uuid_t *uuid = get_cached_uuid_t(0);
|
2007-11-15 22:14:46 +01:00
|
|
|
char *str;
|
2007-12-31 04:55:50 +01:00
|
|
|
uuid_rc_t rc;
|
|
|
|
|
|
|
|
rc = uuid_load(uuid, name);
|
|
|
|
if (rc != UUID_RC_OK)
|
|
|
|
pguuid_complain(rc);
|
2007-04-21 19:26:18 +02:00
|
|
|
str = uuid_to_string(uuid);
|
|
|
|
|
|
|
|
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
|
|
|
|
}
|
|
|
|
|
2014-05-28 01:42:08 +02:00
|
|
|
/* len is unused with OSSP, but we want to have the same number of args */
|
|
|
|
static Datum
|
|
|
|
uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
|
|
|
|
{
|
2014-05-29 19:51:02 +02:00
|
|
|
uuid_t *uuid = get_cached_uuid_t(0);
|
2014-05-28 01:42:08 +02:00
|
|
|
char *str;
|
|
|
|
uuid_rc_t rc;
|
|
|
|
|
|
|
|
rc = uuid_make(uuid, mode, ns, name);
|
|
|
|
if (rc != UUID_RC_OK)
|
|
|
|
pguuid_complain(rc);
|
|
|
|
str = uuid_to_string(uuid);
|
|
|
|
|
|
|
|
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Datum
|
|
|
|
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
|
|
|
|
{
|
2014-05-29 19:51:02 +02:00
|
|
|
uuid_t *ns_uuid = get_cached_uuid_t(1);
|
2014-05-28 01:42:08 +02:00
|
|
|
|
2014-05-29 19:51:02 +02:00
|
|
|
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out,
|
|
|
|
UUIDPGetDatum(ns))),
|
2014-05-28 01:42:08 +02:00
|
|
|
ns_uuid);
|
|
|
|
|
2014-05-29 19:51:02 +02:00
|
|
|
return uuid_generate_internal(mode,
|
|
|
|
ns_uuid,
|
|
|
|
text_to_cstring(name),
|
|
|
|
0);
|
2014-05-28 01:42:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#else /* !HAVE_UUID_OSSP */
|
|
|
|
|
|
|
|
static Datum
|
2017-10-31 15:34:31 +01:00
|
|
|
uuid_generate_internal(int v, unsigned char *ns, const char *ptr, int len)
|
2014-05-28 01:42:08 +02:00
|
|
|
{
|
|
|
|
char strbuf[40];
|
|
|
|
|
|
|
|
switch (v)
|
|
|
|
{
|
2017-06-21 20:39:04 +02:00
|
|
|
case 0: /* constant-value uuids */
|
2014-05-28 01:42:08 +02:00
|
|
|
strlcpy(strbuf, ptr, 37);
|
|
|
|
break;
|
|
|
|
|
2017-06-21 20:39:04 +02:00
|
|
|
case 1: /* time/node-based uuids */
|
2014-05-28 01:42:08 +02:00
|
|
|
{
|
|
|
|
#ifdef HAVE_UUID_E2FS
|
|
|
|
uuid_t uu;
|
|
|
|
|
|
|
|
uuid_generate_time(uu);
|
|
|
|
uuid_unparse(uu, strbuf);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* PTR, if set, replaces the trailing characters of the uuid;
|
|
|
|
* this is to support v1mc, where a random multicast MAC is
|
|
|
|
* used instead of the physical one
|
|
|
|
*/
|
|
|
|
if (ptr && len <= 36)
|
|
|
|
strcpy(strbuf + (36 - len), ptr);
|
|
|
|
#else /* BSD */
|
|
|
|
uuid_t uu;
|
|
|
|
uint32_t status = uuid_s_ok;
|
|
|
|
char *str = NULL;
|
|
|
|
|
|
|
|
uuid_create(&uu, &status);
|
|
|
|
|
|
|
|
if (status == uuid_s_ok)
|
|
|
|
{
|
|
|
|
uuid_to_string(&uu, &str, &status);
|
|
|
|
if (status == uuid_s_ok)
|
|
|
|
{
|
|
|
|
strlcpy(strbuf, str, 37);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* PTR, if set, replaces the trailing characters of
|
|
|
|
* the uuid; this is to support v1mc, where a random
|
|
|
|
* multicast MAC is used instead of the physical one
|
|
|
|
*/
|
|
|
|
if (ptr && len <= 36)
|
|
|
|
strcpy(strbuf + (36 - len), ptr);
|
|
|
|
}
|
|
|
|
if (str)
|
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status != uuid_s_ok)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
|
|
|
|
errmsg("uuid library failure: %d",
|
|
|
|
(int) status)));
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-06-21 20:39:04 +02:00
|
|
|
case 3: /* namespace-based MD5 uuids */
|
|
|
|
case 5: /* namespace-based SHA1 uuids */
|
2014-05-28 01:42:08 +02:00
|
|
|
{
|
|
|
|
dce_uuid_t uu;
|
|
|
|
#ifdef HAVE_UUID_BSD
|
|
|
|
uint32_t status = uuid_s_ok;
|
|
|
|
char *str = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (v == 3)
|
|
|
|
{
|
2020-12-10 04:49:43 +01:00
|
|
|
pg_cryptohash_ctx *ctx = pg_cryptohash_create(PG_MD5);
|
2014-05-28 01:42:08 +02:00
|
|
|
|
2020-12-10 04:49:43 +01:00
|
|
|
if (pg_cryptohash_init(ctx) < 0)
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
elog(ERROR, "could not initialize %s context: %s", "MD5",
|
|
|
|
pg_cryptohash_error(ctx));
|
2020-12-10 04:49:43 +01:00
|
|
|
if (pg_cryptohash_update(ctx, ns, sizeof(uu)) < 0 ||
|
|
|
|
pg_cryptohash_update(ctx, (unsigned char *) ptr, len) < 0)
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
elog(ERROR, "could not update %s context: %s", "MD5",
|
|
|
|
pg_cryptohash_error(ctx));
|
2014-05-28 17:50:41 +02:00
|
|
|
/* we assume sizeof MD5 result is 16, same as UUID size */
|
Add result size as argument of pg_cryptohash_final() for overflow checks
With its current design, a careless use of pg_cryptohash_final() could
would result in an out-of-bound write in memory as the size of the
destination buffer to store the result digest is not known to the
cryptohash internals, without the caller knowing about that. This
commit adds a new argument to pg_cryptohash_final() to allow such sanity
checks, and implements such defenses.
The internals of SCRAM for HMAC could be tightened a bit more, but as
everything is based on SCRAM_KEY_LEN with uses particular to this code
there is no need to complicate its interface more than necessary, and
this comes back to the refactoring of HMAC in core. Except that, this
minimizes the uses of the existing DIGEST_LENGTH variables, relying
instead on sizeof() for the result sizes. In ossp-uuid, this also makes
the code more defensive, as it already relied on dce_uuid_t being at
least the size of a MD5 digest.
This is in philosophy similar to cfc40d3 for base64.c and aef8948 for
hex.c.
Reported-by: Ranier Vilela
Author: Michael Paquier, Ranier Vilela
Reviewed-by: Kyotaro Horiguchi
Discussion: https://postgr.es/m/CAEudQAoqEGmcff3J4sTSV-R_16Monuz-UpJFbf_dnVH=APr02Q@mail.gmail.com
2021-02-15 02:18:34 +01:00
|
|
|
if (pg_cryptohash_final(ctx, (unsigned char *) &uu,
|
|
|
|
sizeof(uu)) < 0)
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
elog(ERROR, "could not finalize %s context: %s", "MD5",
|
|
|
|
pg_cryptohash_error(ctx));
|
2020-12-10 04:49:43 +01:00
|
|
|
pg_cryptohash_free(ctx);
|
2014-05-28 01:42:08 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-23 03:33:04 +01:00
|
|
|
pg_cryptohash_ctx *ctx = pg_cryptohash_create(PG_SHA1);
|
|
|
|
unsigned char sha1result[SHA1_DIGEST_LENGTH];
|
|
|
|
|
|
|
|
if (pg_cryptohash_init(ctx) < 0)
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
elog(ERROR, "could not initialize %s context: %s", "SHA1",
|
|
|
|
pg_cryptohash_error(ctx));
|
2021-01-23 03:33:04 +01:00
|
|
|
if (pg_cryptohash_update(ctx, ns, sizeof(uu)) < 0 ||
|
|
|
|
pg_cryptohash_update(ctx, (unsigned char *) ptr, len) < 0)
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
elog(ERROR, "could not update %s context: %s", "SHA1",
|
|
|
|
pg_cryptohash_error(ctx));
|
Add result size as argument of pg_cryptohash_final() for overflow checks
With its current design, a careless use of pg_cryptohash_final() could
would result in an out-of-bound write in memory as the size of the
destination buffer to store the result digest is not known to the
cryptohash internals, without the caller knowing about that. This
commit adds a new argument to pg_cryptohash_final() to allow such sanity
checks, and implements such defenses.
The internals of SCRAM for HMAC could be tightened a bit more, but as
everything is based on SCRAM_KEY_LEN with uses particular to this code
there is no need to complicate its interface more than necessary, and
this comes back to the refactoring of HMAC in core. Except that, this
minimizes the uses of the existing DIGEST_LENGTH variables, relying
instead on sizeof() for the result sizes. In ossp-uuid, this also makes
the code more defensive, as it already relied on dce_uuid_t being at
least the size of a MD5 digest.
This is in philosophy similar to cfc40d3 for base64.c and aef8948 for
hex.c.
Reported-by: Ranier Vilela
Author: Michael Paquier, Ranier Vilela
Reviewed-by: Kyotaro Horiguchi
Discussion: https://postgr.es/m/CAEudQAoqEGmcff3J4sTSV-R_16Monuz-UpJFbf_dnVH=APr02Q@mail.gmail.com
2021-02-15 02:18:34 +01:00
|
|
|
if (pg_cryptohash_final(ctx, sha1result, sizeof(sha1result)) < 0)
|
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code paths
related to MD5 (frontend and backend) that relied on the fact that the
only type of error that could happen would be an OOM, as the MD5
implementation used in PostgreSQL ~13 (the in-core implementation is
used when compiling with or without OpenSSL in those older versions),
could fail only under this circumstance.
The new cryptohash facilities can fail for reasons other than OOMs, like
attempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to
1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so this
would cause incorrect reports to show up.
This commit extends the cryptohash APIs so as callers of those routines
can fetch more context when an error happens, by using a new routine
called pg_cryptohash_error(). The error states are stored within each
implementation's internal context data, so as it is possible to extend
the logic depending on what's suited for an implementation. The default
implementation requires few error states, but OpenSSL could report
various issues depending on its internal state so more is needed in
cryptohash_openssl.c, and the code is shaped so as we are always able to
grab the necessary information.
The core code is changed to adapt to the new error routine, painting
more "const" across the call stack where the static errors are stored,
particularly in authentication code paths on variables that provide
log details. This way, any future changes would warn if attempting to
free these strings. The MD5 authentication code was also a bit blurry
about the handling of "logdetail" (LOG sent to the postmaster), so
improve the comments related that, while on it.
The origin of the problem is 87ae969, that introduced the centralized
cryptohash facility. Extra changes are done for pgcrypto in v14 for the
non-OpenSSL code path to cope with the improvements done by this
commit.
Reported-by: Michael Mühlbeyer
Author: Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.com
Backpatch-through: 14
2022-01-11 01:55:16 +01:00
|
|
|
elog(ERROR, "could not finalize %s context: %s", "SHA1",
|
|
|
|
pg_cryptohash_error(ctx));
|
2021-01-23 03:33:04 +01:00
|
|
|
pg_cryptohash_free(ctx);
|
2014-05-28 01:42:08 +02:00
|
|
|
|
2014-05-28 17:50:41 +02:00
|
|
|
memcpy(&uu, sha1result, sizeof(uu));
|
2014-05-28 01:42:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* the calculated hash is using local order */
|
|
|
|
UUID_TO_NETWORK(uu);
|
|
|
|
UUID_V3_OR_V5(uu, v);
|
|
|
|
|
|
|
|
#ifdef HAVE_UUID_E2FS
|
|
|
|
/* uuid_unparse expects local order */
|
|
|
|
UUID_TO_LOCAL(uu);
|
|
|
|
uuid_unparse((unsigned char *) &uu, strbuf);
|
|
|
|
#else /* BSD */
|
|
|
|
uuid_to_string(&uu, &str, &status);
|
|
|
|
|
|
|
|
if (status == uuid_s_ok)
|
|
|
|
strlcpy(strbuf, str, 37);
|
|
|
|
|
|
|
|
if (str)
|
|
|
|
free(str);
|
|
|
|
|
|
|
|
if (status != uuid_s_ok)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
|
|
|
|
errmsg("uuid library failure: %d",
|
|
|
|
(int) status)));
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-06-21 20:39:04 +02:00
|
|
|
case 4: /* random uuid */
|
2014-05-28 01:42:08 +02:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
#ifdef HAVE_UUID_E2FS
|
|
|
|
uuid_t uu;
|
|
|
|
|
|
|
|
uuid_generate_random(uu);
|
|
|
|
uuid_unparse(uu, strbuf);
|
|
|
|
#else /* BSD */
|
|
|
|
snprintf(strbuf, sizeof(strbuf),
|
|
|
|
"%08lx-%04x-%04x-%04x-%04x%08lx",
|
|
|
|
(unsigned long) arc4random(),
|
|
|
|
(unsigned) (arc4random() & 0xffff),
|
|
|
|
(unsigned) ((arc4random() & 0xfff) | 0x4000),
|
|
|
|
(unsigned) ((arc4random() & 0x3fff) | 0x8000),
|
|
|
|
(unsigned) (arc4random() & 0xffff),
|
|
|
|
(unsigned long) arc4random());
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DirectFunctionCall1(uuid_in, CStringGetDatum(strbuf));
|
|
|
|
}
|
|
|
|
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
#endif /* HAVE_UUID_OSSP */
|
2014-05-28 01:42:08 +02:00
|
|
|
|
2007-04-21 19:26:18 +02:00
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_nil(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
2007-04-21 19:26:18 +02:00
|
|
|
return special_uuid_value("nil");
|
2014-05-28 01:42:08 +02:00
|
|
|
#else
|
|
|
|
return uuid_generate_internal(0, NULL,
|
|
|
|
"00000000-0000-0000-0000-000000000000", 36);
|
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_ns_dns(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
2007-04-21 19:26:18 +02:00
|
|
|
return special_uuid_value("ns:DNS");
|
2014-05-28 01:42:08 +02:00
|
|
|
#else
|
|
|
|
return uuid_generate_internal(0, NULL,
|
|
|
|
"6ba7b810-9dad-11d1-80b4-00c04fd430c8", 36);
|
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_ns_url(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
2007-04-21 19:26:18 +02:00
|
|
|
return special_uuid_value("ns:URL");
|
2014-05-28 01:42:08 +02:00
|
|
|
#else
|
|
|
|
return uuid_generate_internal(0, NULL,
|
|
|
|
"6ba7b811-9dad-11d1-80b4-00c04fd430c8", 36);
|
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_ns_oid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
2007-04-21 19:26:18 +02:00
|
|
|
return special_uuid_value("ns:OID");
|
2014-05-28 01:42:08 +02:00
|
|
|
#else
|
|
|
|
return uuid_generate_internal(0, NULL,
|
|
|
|
"6ba7b812-9dad-11d1-80b4-00c04fd430c8", 36);
|
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_ns_x500(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
2007-04-21 19:26:18 +02:00
|
|
|
return special_uuid_value("ns:X500");
|
2014-05-28 01:42:08 +02:00
|
|
|
#else
|
|
|
|
return uuid_generate_internal(0, NULL,
|
|
|
|
"6ba7b814-9dad-11d1-80b4-00c04fd430c8", 36);
|
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_generate_v1(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
return uuid_generate_internal(UUID_MAKE_V1, NULL, NULL, 0);
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_generate_v1mc(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
|
|
|
char *buf = NULL;
|
|
|
|
#elif defined(HAVE_UUID_E2FS)
|
|
|
|
char strbuf[40];
|
|
|
|
char *buf;
|
|
|
|
uuid_t uu;
|
|
|
|
|
|
|
|
uuid_generate_random(uu);
|
|
|
|
|
|
|
|
/* set IEEE802 multicast and local-admin bits */
|
|
|
|
((dce_uuid_t *) &uu)->node[0] |= 0x03;
|
|
|
|
|
|
|
|
uuid_unparse(uu, strbuf);
|
|
|
|
buf = strbuf + 24;
|
|
|
|
#else /* BSD */
|
|
|
|
char buf[16];
|
|
|
|
|
|
|
|
/* set IEEE802 multicast and local-admin bits */
|
|
|
|
snprintf(buf, sizeof(buf), "-%04x%08lx",
|
|
|
|
(unsigned) ((arc4random() & 0xffff) | 0x0300),
|
|
|
|
(unsigned long) arc4random());
|
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
|
2014-05-28 01:42:08 +02:00
|
|
|
return uuid_generate_internal(UUID_MAKE_V1 | UUID_MAKE_MC, NULL,
|
|
|
|
buf, 13);
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_generate_v3(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
pg_uuid_t *ns = PG_GETARG_UUID_P(0);
|
2017-03-13 00:35:34 +01:00
|
|
|
text *name = PG_GETARG_TEXT_PP(1);
|
2007-04-21 19:26:18 +02:00
|
|
|
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
2007-04-21 19:26:18 +02:00
|
|
|
return uuid_generate_v35_internal(UUID_MAKE_V3, ns, name);
|
2014-05-28 01:42:08 +02:00
|
|
|
#else
|
|
|
|
return uuid_generate_internal(UUID_MAKE_V3, (unsigned char *) ns,
|
2017-03-13 00:35:34 +01:00
|
|
|
VARDATA_ANY(name), VARSIZE_ANY_EXHDR(name));
|
2014-05-28 01:42:08 +02:00
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_generate_v4(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2014-05-28 01:42:08 +02:00
|
|
|
return uuid_generate_internal(UUID_MAKE_V4, NULL, NULL, 0);
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
uuid_generate_v5(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
pg_uuid_t *ns = PG_GETARG_UUID_P(0);
|
2017-03-13 00:35:34 +01:00
|
|
|
text *name = PG_GETARG_TEXT_PP(1);
|
2007-04-21 19:26:18 +02:00
|
|
|
|
2014-05-28 01:42:08 +02:00
|
|
|
#ifdef HAVE_UUID_OSSP
|
2007-04-21 19:26:18 +02:00
|
|
|
return uuid_generate_v35_internal(UUID_MAKE_V5, ns, name);
|
2014-05-28 01:42:08 +02:00
|
|
|
#else
|
|
|
|
return uuid_generate_internal(UUID_MAKE_V5, (unsigned char *) ns,
|
2017-03-13 00:35:34 +01:00
|
|
|
VARDATA_ANY(name), VARSIZE_ANY_EXHDR(name));
|
2014-05-28 01:42:08 +02:00
|
|
|
#endif
|
2007-04-21 19:26:18 +02:00
|
|
|
}
|