1 /*-------------------------------------------------------------------------
4 * The front-end (client) encryption support for GSSAPI
6 * Portions Copyright (c) 2016-2025, PostgreSQL Global Development Group
9 * src/interfaces/libpq/fe-secure-gssapi.c
11 *-------------------------------------------------------------------------
14 #include "postgres_fe.h"
16 #include "fe-gssapi-common.h"
18 #include "libpq-int.h"
19 #include "port/pg_bswap.h"
23 * Require encryption support, as well as mutual authentication and
24 * tamperproofing measures.
26 #define GSS_REQUIRED_FLAGS GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \
27 GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG
30 * Handle the encryption/decryption of data using GSSAPI.
32 * In the encrypted data stream on the wire, we break up the data
33 * into packets where each packet starts with a uint32-size length
34 * word (in network byte order), then encrypted data of that length
35 * immediately following. Decryption yields the same data stream
36 * that would appear when not using encryption.
38 * Encrypted data typically ends up being larger than the same data
39 * unencrypted, so we use fixed-size buffers for handling the
40 * encryption/decryption which are larger than PQComm's buffer will
41 * typically be to minimize the times where we have to make multiple
42 * packets (and therefore multiple recv/send calls for a single
43 * read/write call to us).
45 * NOTE: The client and server have to agree on the max packet size,
46 * because we have to pass an entire packet to GSSAPI at a time and we
47 * don't want the other side to send arbitrarily huge packets as we
48 * would have to allocate memory for them to then pass them to GSSAPI.
50 * Therefore, these two #define's are effectively part of the protocol
51 * spec and can't ever be changed.
53 #define PQ_GSS_SEND_BUFFER_SIZE 16384
54 #define PQ_GSS_RECV_BUFFER_SIZE 16384
57 * We need these state variables per-connection. To allow the functions
58 * in this file to look mostly like those in be-secure-gssapi.c, set up
61 #define PqGSSSendBuffer (conn->gss_SendBuffer)
62 #define PqGSSSendLength (conn->gss_SendLength)
63 #define PqGSSSendNext (conn->gss_SendNext)
64 #define PqGSSSendConsumed (conn->gss_SendConsumed)
65 #define PqGSSRecvBuffer (conn->gss_RecvBuffer)
66 #define PqGSSRecvLength (conn->gss_RecvLength)
67 #define PqGSSResultBuffer (conn->gss_ResultBuffer)
68 #define PqGSSResultLength (conn->gss_ResultLength)
69 #define PqGSSResultNext (conn->gss_ResultNext)
70 #define PqGSSMaxPktSize (conn->gss_MaxPktSize)
74 * Attempt to write len bytes of data from ptr to a GSSAPI-encrypted connection.
76 * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
77 * transport negotiation is complete).
79 * On success, returns the number of data bytes consumed (possibly less than
80 * len). On failure, returns -1 with errno set appropriately. If the errno
81 * indicates a non-retryable error, a message is added to conn->errorMessage.
82 * For retryable errors, caller should call again (passing the same or more
83 * data) once the socket is ready.
86 pg_GSS_write(PGconn
*conn
, const void *ptr
, size_t len
)
90 gss_buffer_desc input
,
91 output
= GSS_C_EMPTY_BUFFER
;
93 size_t bytes_to_encrypt
;
94 size_t bytes_encrypted
;
95 gss_ctx_id_t gctx
= conn
->gctx
;
98 * When we get a retryable failure, we must not tell the caller we have
99 * successfully transmitted everything, else it won't retry. For
100 * simplicity, we claim we haven't transmitted anything until we have
101 * successfully transmitted all "len" bytes. Between calls, the amount of
102 * the current input data that's already been encrypted and placed into
103 * PqGSSSendBuffer (and perhaps transmitted) is remembered in
104 * PqGSSSendConsumed. On a retry, the caller *must* be sending that data
105 * again, so if it offers a len less than that, something is wrong.
107 * Note: it may seem attractive to report partial write completion once
108 * we've successfully sent any encrypted packets. However, that can cause
109 * problems for callers; notably, pqPutMsgEnd's heuristic to send only
110 * full 8K blocks interacts badly with such a hack. We won't save much,
111 * typically, by letting callers discard data early, so don't risk it.
113 if (len
< PqGSSSendConsumed
)
115 appendPQExpBufferStr(&conn
->errorMessage
,
116 "GSSAPI caller failed to retransmit all data needing to be retried\n");
121 /* Discount whatever source data we already encrypted. */
122 bytes_to_encrypt
= len
- PqGSSSendConsumed
;
123 bytes_encrypted
= PqGSSSendConsumed
;
126 * Loop through encrypting data and sending it out until it's all done or
127 * pqsecure_raw_write() complains (which would likely mean that the socket
128 * is non-blocking and the requested send() would block, or there was some
129 * kind of actual error).
131 while (bytes_to_encrypt
|| PqGSSSendLength
)
137 * Check if we have data in the encrypted output buffer that needs to
138 * be sent (possibly left over from a previous call), and if so, try
139 * to send it. If we aren't able to, return that fact back up to the
145 ssize_t amount
= PqGSSSendLength
- PqGSSSendNext
;
147 retval
= pqsecure_raw_write(conn
, PqGSSSendBuffer
+ PqGSSSendNext
, amount
);
152 * Check if this was a partial write, and if so, move forward that
153 * far in our buffer and try again.
157 PqGSSSendNext
+= retval
;
161 /* We've successfully sent whatever data was in the buffer. */
162 PqGSSSendLength
= PqGSSSendNext
= 0;
166 * Check if there are any bytes left to encrypt. If not, we're done.
168 if (!bytes_to_encrypt
)
172 * Check how much we are being asked to send, if it's too much, then
173 * we will have to loop and possibly be called multiple times to get
174 * through all the data.
176 if (bytes_to_encrypt
> PqGSSMaxPktSize
)
177 input
.length
= PqGSSMaxPktSize
;
179 input
.length
= bytes_to_encrypt
;
181 input
.value
= (char *) ptr
+ bytes_encrypted
;
187 * Create the next encrypted packet. Any failure here is considered a
188 * hard failure, so we return -1 even if some data has been sent.
190 major
= gss_wrap(&minor
, gctx
, 1, GSS_C_QOP_DEFAULT
,
191 &input
, &conf_state
, &output
);
192 if (major
!= GSS_S_COMPLETE
)
194 pg_GSS_error(libpq_gettext("GSSAPI wrap error"), conn
, major
, minor
);
195 errno
= EIO
; /* for lack of a better idea */
201 libpq_append_conn_error(conn
, "outgoing GSSAPI message would not use confidentiality");
202 errno
= EIO
; /* for lack of a better idea */
206 if (output
.length
> PQ_GSS_SEND_BUFFER_SIZE
- sizeof(uint32
))
208 libpq_append_conn_error(conn
, "client tried to send oversize GSSAPI packet (%zu > %zu)",
209 (size_t) output
.length
,
210 PQ_GSS_SEND_BUFFER_SIZE
- sizeof(uint32
));
211 errno
= EIO
; /* for lack of a better idea */
215 bytes_encrypted
+= input
.length
;
216 bytes_to_encrypt
-= input
.length
;
217 PqGSSSendConsumed
+= input
.length
;
219 /* 4 network-order bytes of length, then payload */
220 netlen
= pg_hton32(output
.length
);
221 memcpy(PqGSSSendBuffer
+ PqGSSSendLength
, &netlen
, sizeof(uint32
));
222 PqGSSSendLength
+= sizeof(uint32
);
224 memcpy(PqGSSSendBuffer
+ PqGSSSendLength
, output
.value
, output
.length
);
225 PqGSSSendLength
+= output
.length
;
227 /* Release buffer storage allocated by GSSAPI */
228 gss_release_buffer(&minor
, &output
);
231 /* If we get here, our counters should all match up. */
232 Assert(len
== PqGSSSendConsumed
);
233 Assert(len
== bytes_encrypted
);
235 /* We're reporting all the data as sent, so reset PqGSSSendConsumed. */
236 PqGSSSendConsumed
= 0;
238 ret
= bytes_encrypted
;
241 /* Release GSSAPI buffer storage, if we didn't already */
242 if (output
.value
!= NULL
)
243 gss_release_buffer(&minor
, &output
);
248 * Read up to len bytes of data into ptr from a GSSAPI-encrypted connection.
250 * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
251 * transport negotiation is complete).
253 * Returns the number of data bytes read, or on failure, returns -1
254 * with errno set appropriately. If the errno indicates a non-retryable
255 * error, a message is added to conn->errorMessage. For retryable errors,
256 * caller should call again once the socket is ready.
259 pg_GSS_read(PGconn
*conn
, void *ptr
, size_t len
)
263 gss_buffer_desc input
= GSS_C_EMPTY_BUFFER
,
264 output
= GSS_C_EMPTY_BUFFER
;
266 size_t bytes_returned
= 0;
267 gss_ctx_id_t gctx
= conn
->gctx
;
270 * The plan here is to read one incoming encrypted packet into
271 * PqGSSRecvBuffer, decrypt it into PqGSSResultBuffer, and then dole out
272 * data from there to the caller. When we exhaust the current input
273 * packet, read another.
275 while (bytes_returned
< len
)
279 /* Check if we have data in our buffer that we can return immediately */
280 if (PqGSSResultNext
< PqGSSResultLength
)
282 size_t bytes_in_buffer
= PqGSSResultLength
- PqGSSResultNext
;
283 size_t bytes_to_copy
= Min(bytes_in_buffer
, len
- bytes_returned
);
286 * Copy the data from our result buffer into the caller's buffer,
287 * at the point where we last left off filling their buffer.
289 memcpy((char *) ptr
+ bytes_returned
, PqGSSResultBuffer
+ PqGSSResultNext
, bytes_to_copy
);
290 PqGSSResultNext
+= bytes_to_copy
;
291 bytes_returned
+= bytes_to_copy
;
294 * At this point, we've either filled the caller's buffer or
295 * emptied our result buffer. Either way, return to caller. In
296 * the second case, we could try to read another encrypted packet,
297 * but the odds are good that there isn't one available. (If this
298 * isn't true, we chose too small a max packet size.) In any
299 * case, there's no harm letting the caller process the data we've
305 /* Result buffer is empty, so reset buffer pointers */
306 PqGSSResultLength
= PqGSSResultNext
= 0;
309 * Because we chose above to return immediately as soon as we emit
310 * some data, bytes_returned must be zero at this point. Therefore
311 * the failure exits below can just return -1 without worrying about
312 * whether we already emitted some data.
314 Assert(bytes_returned
== 0);
317 * At this point, our result buffer is empty with more bytes being
318 * requested to be read. We are now ready to load the next packet and
319 * decrypt it (entirely) into our result buffer.
322 /* Collect the length if we haven't already */
323 if (PqGSSRecvLength
< sizeof(uint32
))
325 ret
= pqsecure_raw_read(conn
, PqGSSRecvBuffer
+ PqGSSRecvLength
,
326 sizeof(uint32
) - PqGSSRecvLength
);
328 /* If ret <= 0, pqsecure_raw_read already set the correct errno */
332 PqGSSRecvLength
+= ret
;
334 /* If we still haven't got the length, return to the caller */
335 if (PqGSSRecvLength
< sizeof(uint32
))
342 /* Decode the packet length and check for overlength packet */
343 input
.length
= pg_ntoh32(*(uint32
*) PqGSSRecvBuffer
);
345 if (input
.length
> PQ_GSS_RECV_BUFFER_SIZE
- sizeof(uint32
))
347 libpq_append_conn_error(conn
, "oversize GSSAPI packet sent by the server (%zu > %zu)",
348 (size_t) input
.length
,
349 PQ_GSS_RECV_BUFFER_SIZE
- sizeof(uint32
));
350 errno
= EIO
; /* for lack of a better idea */
355 * Read as much of the packet as we are able to on this call into
356 * wherever we left off from the last time we were called.
358 ret
= pqsecure_raw_read(conn
, PqGSSRecvBuffer
+ PqGSSRecvLength
,
359 input
.length
- (PqGSSRecvLength
- sizeof(uint32
)));
360 /* If ret <= 0, pqsecure_raw_read already set the correct errno */
364 PqGSSRecvLength
+= ret
;
366 /* If we don't yet have the whole packet, return to the caller */
367 if (PqGSSRecvLength
- sizeof(uint32
) < input
.length
)
374 * We now have the full packet and we can perform the decryption and
375 * refill our result buffer, then loop back up to pass data back to
376 * the caller. Note that error exits below here must take care of
377 * releasing the gss output buffer.
381 input
.value
= PqGSSRecvBuffer
+ sizeof(uint32
);
383 major
= gss_unwrap(&minor
, gctx
, &input
, &output
, &conf_state
, NULL
);
384 if (major
!= GSS_S_COMPLETE
)
386 pg_GSS_error(libpq_gettext("GSSAPI unwrap error"), conn
,
389 errno
= EIO
; /* for lack of a better idea */
395 libpq_append_conn_error(conn
, "incoming GSSAPI message did not use confidentiality");
397 errno
= EIO
; /* for lack of a better idea */
401 memcpy(PqGSSResultBuffer
, output
.value
, output
.length
);
402 PqGSSResultLength
= output
.length
;
404 /* Our receive buffer is now empty, reset it */
407 /* Release buffer storage allocated by GSSAPI */
408 gss_release_buffer(&minor
, &output
);
411 ret
= bytes_returned
;
414 /* Release GSSAPI buffer storage, if we didn't already */
415 if (output
.value
!= NULL
)
416 gss_release_buffer(&minor
, &output
);
421 * Simple wrapper for reading from pqsecure_raw_read.
423 * This takes the same arguments as pqsecure_raw_read, plus an output parameter
424 * to return the number of bytes read. This handles if blocking would occur and
425 * if we detect EOF on the connection.
427 static PostgresPollingStatusType
428 gss_read(PGconn
*conn
, void *recv_buffer
, size_t length
, ssize_t
*ret
)
430 *ret
= pqsecure_raw_read(conn
, recv_buffer
, length
);
433 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
434 return PGRES_POLLING_READING
;
436 return PGRES_POLLING_FAILED
;
442 int result
= pqReadReady(conn
);
445 return PGRES_POLLING_FAILED
;
448 return PGRES_POLLING_READING
;
450 *ret
= pqsecure_raw_read(conn
, recv_buffer
, length
);
453 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
454 return PGRES_POLLING_READING
;
456 return PGRES_POLLING_FAILED
;
459 return PGRES_POLLING_FAILED
;
462 return PGRES_POLLING_OK
;
466 * Negotiate GSSAPI transport for a connection. When complete, returns
467 * PGRES_POLLING_OK. Will return PGRES_POLLING_READING or
468 * PGRES_POLLING_WRITING as appropriate whenever it would block, and
469 * PGRES_POLLING_FAILED if transport could not be negotiated.
471 PostgresPollingStatusType
472 pqsecure_open_gss(PGconn
*conn
)
477 gss_flags
= GSS_REQUIRED_FLAGS
;
479 PostgresPollingStatusType result
;
480 gss_buffer_desc input
= GSS_C_EMPTY_BUFFER
,
481 output
= GSS_C_EMPTY_BUFFER
;
484 * If first time through for this connection, allocate buffers and
485 * initialize state variables. By malloc'ing the buffers separately, we
486 * ensure that they are sufficiently aligned for the length-word accesses
487 * that we do in some places in this file.
489 if (PqGSSSendBuffer
== NULL
)
491 PqGSSSendBuffer
= malloc(PQ_GSS_SEND_BUFFER_SIZE
);
492 PqGSSRecvBuffer
= malloc(PQ_GSS_RECV_BUFFER_SIZE
);
493 PqGSSResultBuffer
= malloc(PQ_GSS_RECV_BUFFER_SIZE
);
494 if (!PqGSSSendBuffer
|| !PqGSSRecvBuffer
|| !PqGSSResultBuffer
)
496 libpq_append_conn_error(conn
, "out of memory");
497 return PGRES_POLLING_FAILED
;
499 PqGSSSendLength
= PqGSSSendNext
= PqGSSSendConsumed
= 0;
500 PqGSSRecvLength
= PqGSSResultLength
= PqGSSResultNext
= 0;
504 * Check if we have anything to send from a prior call and if so, send it.
508 ssize_t amount
= PqGSSSendLength
- PqGSSSendNext
;
510 ret
= pqsecure_raw_write(conn
, PqGSSSendBuffer
+ PqGSSSendNext
, amount
);
513 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
)
514 return PGRES_POLLING_WRITING
;
516 return PGRES_POLLING_FAILED
;
521 PqGSSSendNext
+= ret
;
522 return PGRES_POLLING_WRITING
;
525 PqGSSSendLength
= PqGSSSendNext
= 0;
529 * Client sends first, and sending creates a context, therefore this will
530 * be false the first time through, and then when we get called again we
531 * will check for incoming data.
535 /* Process any incoming data we might have */
537 /* See if we are still trying to get the length */
538 if (PqGSSRecvLength
< sizeof(uint32
))
540 /* Attempt to get the length first */
541 result
= gss_read(conn
, PqGSSRecvBuffer
+ PqGSSRecvLength
, sizeof(uint32
) - PqGSSRecvLength
, &ret
);
542 if (result
!= PGRES_POLLING_OK
)
545 PqGSSRecvLength
+= ret
;
547 if (PqGSSRecvLength
< sizeof(uint32
))
548 return PGRES_POLLING_READING
;
552 * Check if we got an error packet
554 * This is safe to do because we shouldn't ever get a packet over 8192
555 * and therefore the actual length bytes, being that they are in
556 * network byte order, for any real packet will start with two zero
559 if (PqGSSRecvBuffer
[0] == 'E')
562 * For an error packet during startup, we don't get a length, so
563 * simply read as much as we can fit into our buffer (as a string,
564 * so leave a spot at the end for a NULL byte too) and report that
565 * back to the caller.
567 result
= gss_read(conn
, PqGSSRecvBuffer
+ PqGSSRecvLength
, PQ_GSS_RECV_BUFFER_SIZE
- PqGSSRecvLength
- 1, &ret
);
568 if (result
!= PGRES_POLLING_OK
)
571 PqGSSRecvLength
+= ret
;
573 Assert(PqGSSRecvLength
< PQ_GSS_RECV_BUFFER_SIZE
);
574 PqGSSRecvBuffer
[PqGSSRecvLength
] = '\0';
575 appendPQExpBuffer(&conn
->errorMessage
, "%s\n", PqGSSRecvBuffer
+ 1);
577 return PGRES_POLLING_FAILED
;
581 * We should have the whole length at this point, so pull it out and
582 * then read whatever we have left of the packet
585 /* Get the length and check for over-length packet */
586 input
.length
= pg_ntoh32(*(uint32
*) PqGSSRecvBuffer
);
587 if (input
.length
> PQ_GSS_RECV_BUFFER_SIZE
- sizeof(uint32
))
589 libpq_append_conn_error(conn
, "oversize GSSAPI packet sent by the server (%zu > %zu)",
590 (size_t) input
.length
,
591 PQ_GSS_RECV_BUFFER_SIZE
- sizeof(uint32
));
592 return PGRES_POLLING_FAILED
;
596 * Read as much of the packet as we are able to on this call into
597 * wherever we left off from the last time we were called.
599 result
= gss_read(conn
, PqGSSRecvBuffer
+ PqGSSRecvLength
,
600 input
.length
- (PqGSSRecvLength
- sizeof(uint32
)), &ret
);
601 if (result
!= PGRES_POLLING_OK
)
604 PqGSSRecvLength
+= ret
;
607 * If we got less than the rest of the packet then we need to return
608 * and be called again.
610 if (PqGSSRecvLength
- sizeof(uint32
) < input
.length
)
611 return PGRES_POLLING_READING
;
613 input
.value
= PqGSSRecvBuffer
+ sizeof(uint32
);
616 /* Load the service name (no-op if already done */
617 ret
= pg_GSS_load_servicename(conn
);
618 if (ret
!= STATUS_OK
)
619 return PGRES_POLLING_FAILED
;
621 if (conn
->gssdelegation
&& conn
->gssdelegation
[0] == '1')
623 /* Acquire credentials if possible */
624 if (conn
->gcred
== GSS_C_NO_CREDENTIAL
)
625 (void) pg_GSS_have_cred_cache(&conn
->gcred
);
628 * We have credentials and gssdelegation is enabled, so request
629 * credential delegation. This may or may not actually result in
630 * credentials being delegated- it depends on if the forwardable flag
631 * has been set in the credential and if the server is configured to
632 * accept delegated credentials.
634 if (conn
->gcred
!= GSS_C_NO_CREDENTIAL
)
635 gss_flags
|= GSS_C_DELEG_FLAG
;
639 * Call GSS init context, either with an empty input, or with a complete
640 * packet from the server.
642 major
= gss_init_sec_context(&minor
, conn
->gcred
, &conn
->gctx
,
643 conn
->gtarg_nam
, GSS_C_NO_OID
,
644 gss_flags
, 0, 0, &input
, NULL
,
645 &output
, NULL
, NULL
);
647 /* GSS Init Sec Context uses the whole packet, so clear it */
650 if (GSS_ERROR(major
))
652 pg_GSS_error(libpq_gettext("could not initiate GSSAPI security context"),
654 return PGRES_POLLING_FAILED
;
657 if (output
.length
== 0)
660 * We're done - hooray! Set flag to tell the low-level I/O routines
661 * to do GSS wrapping/unwrapping.
664 conn
->gssapi_used
= true;
667 gss_release_cred(&minor
, &conn
->gcred
);
668 conn
->gcred
= GSS_C_NO_CREDENTIAL
;
669 gss_release_buffer(&minor
, &output
);
672 * Determine the max packet size which will fit in our buffer, after
673 * accounting for the length. pg_GSS_write will need this.
675 major
= gss_wrap_size_limit(&minor
, conn
->gctx
, 1, GSS_C_QOP_DEFAULT
,
676 PQ_GSS_SEND_BUFFER_SIZE
- sizeof(uint32
),
679 if (GSS_ERROR(major
))
681 pg_GSS_error(libpq_gettext("GSSAPI size check error"), conn
,
683 return PGRES_POLLING_FAILED
;
686 return PGRES_POLLING_OK
;
689 /* Must have output.length > 0 */
690 if (output
.length
> PQ_GSS_SEND_BUFFER_SIZE
- sizeof(uint32
))
692 pg_GSS_error(libpq_gettext("GSSAPI context establishment error"),
694 gss_release_buffer(&minor
, &output
);
695 return PGRES_POLLING_FAILED
;
698 /* Queue the token for writing */
699 netlen
= pg_hton32(output
.length
);
701 memcpy(PqGSSSendBuffer
, (char *) &netlen
, sizeof(uint32
));
702 PqGSSSendLength
+= sizeof(uint32
);
704 memcpy(PqGSSSendBuffer
+ PqGSSSendLength
, output
.value
, output
.length
);
705 PqGSSSendLength
+= output
.length
;
707 /* We don't bother with PqGSSSendConsumed here */
709 /* Release buffer storage allocated by GSSAPI */
710 gss_release_buffer(&minor
, &output
);
712 /* Ask to be called again to write data */
713 return PGRES_POLLING_WRITING
;
717 * GSSAPI Information functions.
721 * Return the GSSAPI Context itself.
724 PQgetgssctx(PGconn
*conn
)
733 * Return true if GSSAPI encryption is in use.
736 PQgssEncInUse(PGconn
*conn
)
738 if (!conn
|| !conn
->gctx
)