[gnutls-devel] GnuTLS | Segfault during handshake on server connection if no private key is supplied (#1412)
Read-only notification of GnuTLS library development activities
gnutls-devel at lists.gnutls.org
Tue Oct 4 12:05:49 CEST 2022
Sebastian Dröge created an issue: https://gitlab.com/gnutls/gnutls/-/issues/1412
When providing credentials without a private key then `gnutls_handshake()` will segfault. This is obviously an application bug but it would be great if GnuTLS could also catch this in a better way, either with an actual assertion or with a handshake error.
valgrind reports the following with the attached server application (based on the echo server example from the docs):
```
==427258== Invalid read of size 4
==427258== at 0x490617D: _gnutls_privkey_compatible_with_sig (privkey.c:1966)
==427258== by 0x499BD22: _gnutls_session_get_sign_algo (signature.c:381)
==427258== by 0x49A94BC: cert_select_sign_algorithm (cert.c:1591)
==427258== by 0x49AC308: _gnutls_select_server_cert (cert.c:1643)
==427258== by 0x49B778D: _gnutls_figure_common_ciphersuite (ciphersuites.c:1526)
==427258== by 0x48D01C1: _gnutls_server_select_suite (handshake.c:1158)
==427258== by 0x48D2FBC: read_client_hello (handshake.c:862)
==427258== by 0x48D2FBC: _gnutls_recv_handshake (handshake.c:1641)
==427258== by 0x48D6368: handshake_server (handshake.c:3496)
==427258== by 0x48D6368: gnutls_handshake (handshake.c:2886)
==427258== by 0x1097B0: main (test.c:127)
==427258== Address 0x4 is not stack'd, malloc'd or (recently) free'd
```
Testcase application
```cpp
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <gnutls/gnutls.h>
#include <gnutls/urls.h>
#include <gnutls/x509.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define CHECK(x) assert((x) >= 0)
#define LOOP_CHECK(rval, cmd) \
do { \
rval = cmd; \
} while (rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED)
#define MAX_BUF 1024
#define PORT 5556
const unsigned char cert_data[] = "-----BEGIN CERTIFICATE----- \
MIIEQDCCAqigAwIBAgIRAO5XT7tkYlNt77CBj2H5HiEwDQYJKoZIhvcNAQELBQAw \
czEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSQwIgYDVQQLDBtqbWFs \
dmVzQHBvcC1vcyAoSm9hbyBBbHZlcykxKzApBgNVBAMMIm1rY2VydCBqbWFsdmVz \
QHBvcC1vcyAoSm9hbyBBbHZlcykwHhcNMjIwOTIyMTIyNTMzWhcNMjQxMjIyMTMy \
NTMzWjBPMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUx \
JDAiBgNVBAsMG2ptYWx2ZXNAcG9wLW9zIChKb2FvIEFsdmVzKTCCASIwDQYJKoZI \
hvcNAQEBBQADggEPADCCAQoCggEBAJPz8CCFHtNsSzbc64tR/7B1Kf1xuxDz0cBS \
vAlEYzfaBrPmgV3zoaIgKnW9u8EWwvRXzhVLfMnO/x8jfIRmSDDK1M+fXmriIDkx \
5cbWnCN2GQ81P/GdvsGpx2XWBpKTCYQm/6EvdvAsg0+GWrgSxo4hFg59YLaWeWHj \
PTSKABM9C63X9UnQKvP25rYkJ42znnkmqmGXCe1iPk1xZvDfqcbZ1sZXlMV2dS9M \
CRu6Dwqo7N3hVbwM/vZ4X7vWH6JRT8Soz6CijWDcAVvusrxx0QyNQg4nuQznZrnW \
nQbjmEQf4MCO4OCd5uh5rXcxvdYZbpMx25EujMbh0OWfecC+GH8CAwEAAaNzMHEw \
DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaA \
FIwNqPZz6OxXFjHo/y0pAHyU3Q2TMCkGA1UdEQQiMCCCCWxvY2FsaG9zdIINZHMu \
YWl2ZXJvLmxhbocEfwAAATANBgkqhkiG9w0BAQsFAAOCAYEAiPa2QzuPK9FckgW+ \
FBu0fwsjBY+DOhhLzj7Su2eEg0hQDuV8A8hwbj6lfvY0UGOh6Tb6fjs/daUaQLcK \
k5och7JbHiauch5hVx2xmXCcJu55sLW9UcJHOSvP+jalUm1BqlMWHIAcbFwajOWV \
tXENgRleSkFmw2uoi66lQq8QBHDosUKJukZQnweXihWXoZ2pWPkaOY3cBc2DYpBM \
8ioyW6mdyG1Ot4vT5En+WauGJCFKAzvPtM74HNp9kw+ddLqPamTTbMtm78gi8B7E \
eHPYBedjEvaroY5lw1iU6n5VNiF61Ygc3vC4QSCIBNOOMUEXwK0c3gzF9DrpCBXY \
ezVYCmgnM5FfeJ/l25DhpPdUTD+MJJ3dZd+AB4Kx7a0dI5xWelaZCExa+yr8UWYd \
hsrOnFMTWHMjlx+kzWxC4U+bHAxX4buQpq37l9GyASldbLGdqA86Dnaxit3nhZPb \
GO+ToIks+22GnP8wLvWWTZc3wV90RhRDy5GkZzDX7K8J1/C0 \
-----END CERTIFICATE-----";
static const gnutls_datum_t cert_pem = {
.data = (unsigned char *)cert_data,
.size = sizeof(cert_data),
};
static gnutls_x509_crt_t cert;
static gnutls_privkey_t privkey;
static gnutls_certificate_credentials_t creds;
static int retrieve_func(gnutls_session_t session,
const gnutls_datum_t *req_ca_rdn, int nreqs,
const gnutls_pk_algorithm_t *pk_algos,
int pk_algos_length, gnutls_pcert_st **pcert,
unsigned int *pcert_length, gnutls_privkey_t *pkey) {
*pcert = malloc(sizeof(gnutls_pcert_st));
gnutls_pcert_import_x509(*pcert, cert, 0);
*pcert_length = 1;
*pkey = *pkey;
return 0;
}
int main(void) {
int listen_sd;
int sd, ret;
gnutls_priority_t priority_cache;
struct sockaddr_in sa_serv;
struct sockaddr_in sa_cli;
socklen_t client_len;
char topbuf[512];
gnutls_session_t session;
char buffer[MAX_BUF + 1];
int optval = 1;
CHECK(gnutls_global_init());
CHECK(gnutls_x509_crt_init(&cert));
CHECK(gnutls_x509_crt_import(cert, &cert_pem, GNUTLS_X509_FMT_PEM));
CHECK(gnutls_privkey_init(&privkey));
CHECK(gnutls_certificate_allocate_credentials(&creds));
gnutls_certificate_set_retrieve_function2(creds, retrieve_func);
CHECK(gnutls_priority_init(&priority_cache, NULL, NULL));
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
memset(&sa_serv, '\0', sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons(PORT); /* Server Port number */
setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int));
bind(listen_sd, (struct sockaddr *)&sa_serv, sizeof(sa_serv));
listen(listen_sd, 1024);
printf("Server ready. Listening to port '%d'.\n\n", PORT);
client_len = sizeof(sa_cli);
for (;;) {
CHECK(gnutls_init(&session, GNUTLS_SERVER));
CHECK(gnutls_priority_set(session, priority_cache));
CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, creds));
gnutls_certificate_server_set_request(session, GNUTLS_CERT_IGNORE);
gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
sd = accept(listen_sd, (struct sockaddr *)&sa_cli, &client_len);
printf("- connection from %s, port %d\n",
inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)),
ntohs(sa_cli.sin_port));
gnutls_transport_set_int(session, sd);
LOOP_CHECK(ret, gnutls_handshake(session));
if (ret < 0) {
close(sd);
gnutls_deinit(session);
fprintf(stderr, "*** Handshake has failed (%s)\n\n",
gnutls_strerror(ret));
continue;
}
printf("- Handshake was completed\n");
for (;;) {
LOOP_CHECK(ret, gnutls_record_recv(session, buffer, MAX_BUF));
if (ret == 0) {
printf("\n- Peer has closed the GnuTLS connection\n");
break;
} else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
} else if (ret < 0) {
fprintf(stderr,
"\n*** Received corrupted "
"data(%d). Closing the connection.\n\n",
ret);
break;
} else if (ret > 0) {
CHECK(gnutls_record_send(session, buffer, ret));
}
}
printf("\n");
LOOP_CHECK(ret, gnutls_bye(session, GNUTLS_SHUT_WR));
close(sd);
gnutls_deinit(session);
}
close(listen_sd);
gnutls_x509_crt_deinit(cert);
gnutls_privkey_deinit(privkey);
gnutls_certificate_free_credentials(creds);
gnutls_priority_deinit(priority_cache);
gnutls_global_deinit();
return 0;
}
```
--
Reply to this email directly or view it on GitLab: https://gitlab.com/gnutls/gnutls/-/issues/1412
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.gnupg.org/pipermail/gnutls-devel/attachments/20221004/1452a021/attachment-0001.html>
More information about the Gnutls-devel
mailing list