Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb69aba7

Browse files
committed
Improve error handling of cryptohash computations
The existing cryptohash facility was causing problems in some code pathsrelated to MD5 (frontend and backend) that relied on the fact that theonly type of error that could happen would be an OOM, as the MD5implementation used in PostgreSQL ~13 (the in-core implementation isused 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, likeattempting MD5 when FIPS is enabled (upstream OpenSSL allows that up to1.0.2, Fedora and Photon patch OpenSSL 1.1.1 to allow that), so thiswould cause incorrect reports to show up.This commit extends the cryptohash APIs so as callers of those routinescan fetch more context when an error happens, by using a new routinecalled pg_cryptohash_error(). The error states are stored within eachimplementation's internal context data, so as it is possible to extendthe logic depending on what's suited for an implementation. The defaultimplementation requires few error states, but OpenSSL could reportvarious issues depending on its internal state so more is needed incryptohash_openssl.c, and the code is shaped so as we are always able tograb the necessary information.The core code is changed to adapt to the new error routine, paintingmore "const" across the call stack where the static errors are stored,particularly in authentication code paths on variables that providelog details. This way, any future changes would warn if attempting tofree these strings. The MD5 authentication code was also a bit blurryabout the handling of "logdetail" (LOG sent to the postmaster), soimprove the comments related that, while on it.The origin of the problem is87ae969, that introduced the centralizedcryptohash facility. Extra changes are done for pgcrypto in v14 for thenon-OpenSSL code path to cope with the improvements done by thiscommit.Reported-by: Michael MühlbeyerAuthor: Michael PaquierReviewed-by: Tom LaneDiscussion:https://postgr.es/m/89B7F072-5BBE-4C92-903E-D83E865D9367@trivadis.comBackpatch-through: 14
1 parent9ef2c65 commitb69aba7

File tree

18 files changed

+275
-77
lines changed

18 files changed

+275
-77
lines changed

‎contrib/passwordcheck/passwordcheck.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ check_password(const char *username,
7474
*
7575
* We only check for username = password.
7676
*/
77-
char*logdetail;
77+
constchar*logdetail=NULL;
7878

7979
if (plain_crypt_verify(username,shadow_pass,username,&logdetail)==STATUS_OK)
8080
ereport(ERROR,

‎contrib/uuid-ossp/uuid-ossp.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,17 @@ uuid_generate_internal(int v, unsigned char *ns, const char *ptr, int len)
319319
pg_cryptohash_ctx*ctx=pg_cryptohash_create(PG_MD5);
320320

321321
if (pg_cryptohash_init(ctx)<0)
322-
elog(ERROR,"could not initialize %s context","MD5");
322+
elog(ERROR,"could not initialize %s context: %s","MD5",
323+
pg_cryptohash_error(ctx));
323324
if (pg_cryptohash_update(ctx,ns,sizeof(uu))<0||
324325
pg_cryptohash_update(ctx, (unsignedchar*)ptr,len)<0)
325-
elog(ERROR,"could not update %s context","MD5");
326+
elog(ERROR,"could not update %s context: %s","MD5",
327+
pg_cryptohash_error(ctx));
326328
/* we assume sizeof MD5 result is 16, same as UUID size */
327329
if (pg_cryptohash_final(ctx, (unsignedchar*)&uu,
328330
sizeof(uu))<0)
329-
elog(ERROR,"could not finalize %s context","MD5");
331+
elog(ERROR,"could not finalize %s context: %s","MD5",
332+
pg_cryptohash_error(ctx));
330333
pg_cryptohash_free(ctx);
331334
}
332335
else
@@ -335,12 +338,15 @@ uuid_generate_internal(int v, unsigned char *ns, const char *ptr, int len)
335338
unsignedcharsha1result[SHA1_DIGEST_LENGTH];
336339

337340
if (pg_cryptohash_init(ctx)<0)
338-
elog(ERROR,"could not initialize %s context","SHA1");
341+
elog(ERROR,"could not initialize %s context: %s","SHA1",
342+
pg_cryptohash_error(ctx));
339343
if (pg_cryptohash_update(ctx,ns,sizeof(uu))<0||
340344
pg_cryptohash_update(ctx, (unsignedchar*)ptr,len)<0)
341-
elog(ERROR,"could not update %s context","SHA1");
345+
elog(ERROR,"could not update %s context: %s","SHA1",
346+
pg_cryptohash_error(ctx));
342347
if (pg_cryptohash_final(ctx,sha1result,sizeof(sha1result))<0)
343-
elog(ERROR,"could not finalize %s context","SHA1");
348+
elog(ERROR,"could not finalize %s context: %s","SHA1",
349+
pg_cryptohash_error(ctx));
344350
pg_cryptohash_free(ctx);
345351

346352
memcpy(&uu,sha1result,sizeof(uu));

‎src/backend/commands/user.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
355355
if (password)
356356
{
357357
char*shadow_pass;
358-
char*logdetail;
358+
constchar*logdetail=NULL;
359359

360360
/*
361361
* Don't allow an empty password. Libpq treats an empty password the
@@ -775,7 +775,7 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
775775
if (password)
776776
{
777777
char*shadow_pass;
778-
char*logdetail;
778+
constchar*logdetail=NULL;
779779

780780
/* Like in CREATE USER, don't allow an empty password. */
781781
if (password[0]=='\0'||

‎src/backend/libpq/auth-sasl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
*/
5151
int
5252
CheckSASLAuth(constpg_be_sasl_mech*mech,Port*port,char*shadow_pass,
53-
char**logdetail)
53+
constchar**logdetail)
5454
{
5555
StringInfoDatasasl_mechs;
5656
intmtype;

‎src/backend/libpq/auth-scram.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ static void scram_get_mechanisms(Port *port, StringInfo buf);
111111
staticvoid*scram_init(Port*port,constchar*selected_mech,
112112
constchar*shadow_pass);
113113
staticintscram_exchange(void*opaq,constchar*input,intinputlen,
114-
char**output,int*outputlen,char**logdetail);
114+
char**output,int*outputlen,
115+
constchar**logdetail);
115116

116117
/* Mechanism declaration */
117118
constpg_be_sasl_mechpg_be_scram_mech= {
@@ -335,7 +336,7 @@ scram_init(Port *port, const char *selected_mech, const char *shadow_pass)
335336
*/
336337
staticint
337338
scram_exchange(void*opaq,constchar*input,intinputlen,
338-
char**output,int*outputlen,char**logdetail)
339+
char**output,int*outputlen,constchar**logdetail)
339340
{
340341
scram_state*state= (scram_state*)opaq;
341342
intresult;

‎src/backend/libpq/auth.c

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* Global authentication functions
4646
*----------------------------------------------------------------
4747
*/
48-
staticvoidauth_failed(Port*port,intstatus,char*logdetail);
48+
staticvoidauth_failed(Port*port,intstatus,constchar*logdetail);
4949
staticchar*recv_password_packet(Port*port);
5050
staticvoidset_authn_id(Port*port,constchar*id);
5151

@@ -54,10 +54,11 @@ static void set_authn_id(Port *port, const char *id);
5454
* Password-based authentication methods (password, md5, and scram-sha-256)
5555
*----------------------------------------------------------------
5656
*/
57-
staticintCheckPasswordAuth(Port*port,char**logdetail);
58-
staticintCheckPWChallengeAuth(Port*port,char**logdetail);
57+
staticintCheckPasswordAuth(Port*port,constchar**logdetail);
58+
staticintCheckPWChallengeAuth(Port*port,constchar**logdetail);
5959

60-
staticintCheckMD5Auth(Port*port,char*shadow_pass,char**logdetail);
60+
staticintCheckMD5Auth(Port*port,char*shadow_pass,
61+
constchar**logdetail);
6162

6263

6364
/*----------------------------------------------------------------
@@ -247,7 +248,7 @@ ClientAuthentication_hook_type ClientAuthentication_hook = NULL;
247248
* particular, if logdetail isn't NULL, we send that string to the log.
248249
*/
249250
staticvoid
250-
auth_failed(Port*port,intstatus,char*logdetail)
251+
auth_failed(Port*port,intstatus,constchar*logdetail)
251252
{
252253
constchar*errstr;
253254
char*cdetail;
@@ -383,7 +384,7 @@ void
383384
ClientAuthentication(Port*port)
384385
{
385386
intstatus=STATUS_ERROR;
386-
char*logdetail=NULL;
387+
constchar*logdetail=NULL;
387388

388389
/*
389390
* Get the authentication method to use for this frontend/database
@@ -769,7 +770,7 @@ recv_password_packet(Port *port)
769770
* Plaintext password authentication.
770771
*/
771772
staticint
772-
CheckPasswordAuth(Port*port,char**logdetail)
773+
CheckPasswordAuth(Port*port,constchar**logdetail)
773774
{
774775
char*passwd;
775776
intresult;
@@ -804,7 +805,7 @@ CheckPasswordAuth(Port *port, char **logdetail)
804805
* MD5 and SCRAM authentication.
805806
*/
806807
staticint
807-
CheckPWChallengeAuth(Port*port,char**logdetail)
808+
CheckPWChallengeAuth(Port*port,constchar**logdetail)
808809
{
809810
intauth_result;
810811
char*shadow_pass;
@@ -866,7 +867,7 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
866867
}
867868

868869
staticint
869-
CheckMD5Auth(Port*port,char*shadow_pass,char**logdetail)
870+
CheckMD5Auth(Port*port,char*shadow_pass,constchar**logdetail)
870871
{
871872
charmd5Salt[4];/* Password salt */
872873
char*passwd;
@@ -3085,6 +3086,8 @@ PerformRadiusTransaction(const char *server, const char *secret, const char *por
30853086
md5trailer=packet->vector;
30863087
for (i=0;i<encryptedpasswordlen;i+=RADIUS_VECTOR_LENGTH)
30873088
{
3089+
constchar*errstr=NULL;
3090+
30883091
memcpy(cryptvector+strlen(secret),md5trailer,RADIUS_VECTOR_LENGTH);
30893092

30903093
/*
@@ -3093,10 +3096,12 @@ PerformRadiusTransaction(const char *server, const char *secret, const char *por
30933096
*/
30943097
md5trailer=encryptedpassword+i;
30953098

3096-
if (!pg_md5_binary(cryptvector,strlen(secret)+RADIUS_VECTOR_LENGTH,encryptedpassword+i))
3099+
if (!pg_md5_binary(cryptvector,strlen(secret)+RADIUS_VECTOR_LENGTH,
3100+
encryptedpassword+i,&errstr))
30973101
{
30983102
ereport(LOG,
3099-
(errmsg("could not perform MD5 encryption of password")));
3103+
(errmsg("could not perform MD5 encryption of password: %s",
3104+
errstr)));
31003105
pfree(cryptvector);
31013106
pg_freeaddrinfo_all(hint.ai_family,serveraddrs);
31023107
returnSTATUS_ERROR;
@@ -3181,6 +3186,7 @@ PerformRadiusTransaction(const char *server, const char *secret, const char *por
31813186
structtimevaltimeout;
31823187
structtimevalnow;
31833188
int64timeoutval;
3189+
constchar*errstr=NULL;
31843190

31853191
gettimeofday(&now,NULL);
31863192
timeoutval= (endtime.tv_sec*1000000+endtime.tv_usec)- (now.tv_sec*1000000+now.tv_usec);
@@ -3299,10 +3305,11 @@ PerformRadiusTransaction(const char *server, const char *secret, const char *por
32993305

33003306
if (!pg_md5_binary(cryptvector,
33013307
packetlength+strlen(secret),
3302-
encryptedpassword))
3308+
encryptedpassword,&errstr))
33033309
{
33043310
ereport(LOG,
3305-
(errmsg("could not perform MD5 encryption of received packet")));
3311+
(errmsg("could not perform MD5 encryption of received packet: %s",
3312+
errstr)));
33063313
pfree(cryptvector);
33073314
continue;
33083315
}

‎src/backend/libpq/crypt.c

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* sent to the client, to avoid giving away user information!
3535
*/
3636
char*
37-
get_role_password(constchar*role,char**logdetail)
37+
get_role_password(constchar*role,constchar**logdetail)
3838
{
3939
TimestampTzvuntil=0;
4040
HeapTupleroleTup;
@@ -116,6 +116,7 @@ encrypt_password(PasswordType target_type, const char *role,
116116
{
117117
PasswordTypeguessed_type=get_password_type(password);
118118
char*encrypted_password;
119+
constchar*errstr=NULL;
119120

120121
if (guessed_type!=PASSWORD_TYPE_PLAINTEXT)
121122
{
@@ -132,8 +133,8 @@ encrypt_password(PasswordType target_type, const char *role,
132133
encrypted_password=palloc(MD5_PASSWD_LEN+1);
133134

134135
if (!pg_md5_encrypt(password,role,strlen(role),
135-
encrypted_password))
136-
elog(ERROR,"password encryption failed");
136+
encrypted_password,&errstr))
137+
elog(ERROR,"password encryption failed: %s",errstr);
137138
returnencrypted_password;
138139

139140
casePASSWORD_TYPE_SCRAM_SHA_256:
@@ -159,17 +160,18 @@ encrypt_password(PasswordType target_type, const char *role,
159160
* 'client_pass' is the response given by the remote user to the MD5 challenge.
160161
* 'md5_salt' is the salt used in the MD5 authentication challenge.
161162
*
162-
* In the error case,optionally store a palloc'dstring at *logdetail
163-
*that will be sent to thepostmaster log (but not the client).
163+
* In the error case,save astring at *logdetail that will be sent to the
164+
* postmaster log (but not the client).
164165
*/
165166
int
166167
md5_crypt_verify(constchar*role,constchar*shadow_pass,
167168
constchar*client_pass,
168169
constchar*md5_salt,intmd5_salt_len,
169-
char**logdetail)
170+
constchar**logdetail)
170171
{
171172
intretval;
172173
charcrypt_pwd[MD5_PASSWD_LEN+1];
174+
constchar*errstr=NULL;
173175

174176
Assert(md5_salt_len>0);
175177

@@ -183,16 +185,13 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
183185

184186
/*
185187
* Compute the correct answer for the MD5 challenge.
186-
*
187-
* We do not bother setting logdetail for any pg_md5_encrypt failure
188-
* below: the only possible error is out-of-memory, which is unlikely, and
189-
* if it did happen adding a psprintf call would only make things worse.
190188
*/
191189
/* stored password already encrypted, only do salt */
192190
if (!pg_md5_encrypt(shadow_pass+strlen("md5"),
193191
md5_salt,md5_salt_len,
194-
crypt_pwd))
192+
crypt_pwd,&errstr))
195193
{
194+
*logdetail=errstr;
196195
returnSTATUS_ERROR;
197196
}
198197

@@ -215,15 +214,16 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
215214
* pg_authid.rolpassword.
216215
* 'client_pass' is the password given by the remote user.
217216
*
218-
* In the error case,optionallystore apalloc'dstring at *logdetail
219-
*that will be sent to thepostmaster log (but not the client).
217+
* In the error case, store a string at *logdetail that will be sent to the
218+
* postmaster log (but not the client).
220219
*/
221220
int
222221
plain_crypt_verify(constchar*role,constchar*shadow_pass,
223222
constchar*client_pass,
224-
char**logdetail)
223+
constchar**logdetail)
225224
{
226225
charcrypt_client_pass[MD5_PASSWD_LEN+1];
226+
constchar*errstr=NULL;
227227

228228
/*
229229
* Client sent password in plaintext. If we have an MD5 hash stored, hash
@@ -251,14 +251,10 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
251251
if (!pg_md5_encrypt(client_pass,
252252
role,
253253
strlen(role),
254-
crypt_client_pass))
254+
crypt_client_pass,
255+
&errstr))
255256
{
256-
/*
257-
* We do not bother setting logdetail for pg_md5_encrypt
258-
* failure: the only possible error is out-of-memory, which is
259-
* unlikely, and if it did happen adding a psprintf call would
260-
* only make things worse.
261-
*/
257+
*logdetail=errstr;
262258
returnSTATUS_ERROR;
263259
}
264260
if (strcmp(crypt_client_pass,shadow_pass)==0)

‎src/backend/replication/backup_manifest.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ InitializeBackupManifest(backup_manifest_info *manifest,
6868
manifest->buffile=BufFileCreateTemp(false);
6969
manifest->manifest_ctx=pg_cryptohash_create(PG_SHA256);
7070
if (pg_cryptohash_init(manifest->manifest_ctx)<0)
71-
elog(ERROR,"failed to initialize checksum of backup manifest");
71+
elog(ERROR,"failed to initialize checksum of backup manifest: %s",
72+
pg_cryptohash_error(manifest->manifest_ctx));
7273
}
7374

7475
manifest->manifest_size=UINT64CONST(0);
@@ -311,7 +312,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
311312
* Finalize the backup manifest, and send it to the client.
312313
*/
313314
void
314-
SendBackupManifest(backup_manifest_info*manifest,bbsink*sink)
315+
SendBackupManifest(backup_manifest_info*manifest,bbsink*sink)
315316
{
316317
uint8checksumbuf[PG_SHA256_DIGEST_LENGTH];
317318
charchecksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH];
@@ -334,7 +335,8 @@ SendBackupManifest(backup_manifest_info *manifest, bbsink *sink)
334335
manifest->still_checksumming= false;
335336
if (pg_cryptohash_final(manifest->manifest_ctx,checksumbuf,
336337
sizeof(checksumbuf))<0)
337-
elog(ERROR,"failed to finalize checksum of backup manifest");
338+
elog(ERROR,"failed to finalize checksum of backup manifest: %s",
339+
pg_cryptohash_error(manifest->manifest_ctx));
338340
AppendStringToManifest(manifest,"\"Manifest-Checksum\": \"");
339341

340342
hex_encode((char*)checksumbuf,sizeofchecksumbuf,checksumstringbuf);
@@ -391,7 +393,8 @@ AppendStringToManifest(backup_manifest_info *manifest, char *s)
391393
if (manifest->still_checksumming)
392394
{
393395
if (pg_cryptohash_update(manifest->manifest_ctx, (uint8*)s,len)<0)
394-
elog(ERROR,"failed to update checksum of backup manifest");
396+
elog(ERROR,"failed to update checksum of backup manifest: %s",
397+
pg_cryptohash_error(manifest->manifest_ctx));
395398
}
396399
BufFileWrite(manifest->buffile,s,len);
397400
manifest->manifest_size+=len;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp