Files
Open_Ultra_SAST/benchmarks/pairs/vfc/curl-cve-2022-27782-nss_setup_connect/fixed.c
T
Marius CiepluchandClaude Fable 5.1 c3e841003c fix(pair-corpus-honesty): re-harvest curl/OpenSSL excerpts, restore Juliet fixtures
Tasks 3.3 and 4.1.

- vfc curl and openssl-cve-2021-3449 excerpts re-harvested through the
  shared library: whole functions with upstream_start headers, the
  vendored key redacted code-safely, no truncated bodies.
- vfc/recipes.toml carries mode, fix_path and function anchors;
  training/manifest.jsonl regenerated.
- Juliet CWE-121 strcpy pair gets its buffer declarations back so the
  vulnerable side is a real overflow again.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
2026-09-05 10:45:42 +02:00

327 lines
9.8 KiB
C

/* Provenance: curl/curl nss_setup_connect (fixed).
* repo: curl/curl
* commit: f18af4f874cecab82a9797e8c7541e0990c7a64c
* parent: 7e92d12b4e6911f424678a133b19de670e183a59
* commit_url: https://github.com/curl/curl/commit/f18af4f874cecab82a9797e8c7541e0990c7a64c
* cve: CVE-2022-27782
* license: curl
* function: nss_setup_connect
* relpath: lib/vtls/nss.c
* provenance: human
* mechanism: other
*/
static CURLcode nss_setup_connect(struct Curl_easy *data,
struct connectdata *conn, int sockindex)
{
PRFileDesc *model = NULL;
PRFileDesc *nspr_io = NULL;
PRFileDesc *nspr_io_stub = NULL;
PRBool ssl_no_cache;
PRBool ssl_cbc_random_iv;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
CURLcode result;
bool second_layer = FALSE;
SSLVersionRange sslver_supported;
SSLVersionRange sslver = {
SSL_LIBRARY_VERSION_TLS_1_0, /* min */
#ifdef SSL_LIBRARY_VERSION_TLS_1_3
SSL_LIBRARY_VERSION_TLS_1_3 /* max */
#elif defined SSL_LIBRARY_VERSION_TLS_1_2
SSL_LIBRARY_VERSION_TLS_1_2
#elif defined SSL_LIBRARY_VERSION_TLS_1_1
SSL_LIBRARY_VERSION_TLS_1_1
#else
SSL_LIBRARY_VERSION_TLS_1_0
#endif
};
char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
if(!snihost) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
DEBUGASSERT(backend);
backend->data = data;
/* list of all NSS objects we need to destroy in nss_do_close() */
Curl_llist_init(&backend->obj_list, nss_destroy_object);
PR_Lock(nss_initlock);
result = nss_setup(data);
if(result) {
PR_Unlock(nss_initlock);
goto error;
}
PK11_SetPasswordFunc(nss_get_password);
result = nss_load_module(&pem_module, pem_library, "PEM");
PR_Unlock(nss_initlock);
if(result == CURLE_FAILED_INIT)
infof(data, "WARNING: failed to load NSS PEM library %s. Using "
"OpenSSL PEM certificates will not work.", pem_library);
else if(result)
goto error;
result = CURLE_SSL_CONNECT_ERROR;
model = PR_NewTCPSocket();
if(!model)
goto error;
model = SSL_ImportFD(NULL, model);
if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
goto error;
if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
goto error;
if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
goto error;
/* do not use SSL cache if disabled or we are not going to verify peer */
ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
&& SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
goto error;
/* enable/disable the requested SSL version(s) */
if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
goto error;
if(SSL_VersionRangeGetSupported(ssl_variant_stream,
&sslver_supported) != SECSuccess)
goto error;
if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) {
char *sslver_req_str, *sslver_supp_str;
sslver_req_str = nss_sslver_to_name(sslver.max);
sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
if(sslver_req_str && sslver_supp_str)
infof(data, "Falling back from %s to max supported SSL version (%s)",
sslver_req_str, sslver_supp_str);
free(sslver_req_str);
free(sslver_supp_str);
sslver.max = sslver_supported.max;
}
if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
goto error;
ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
#ifdef SSL_CBC_RANDOM_IV
/* unless the user explicitly asks to allow the protocol vulnerability, we
use the work-around */
if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
infof(data, "WARNING: failed to set SSL_CBC_RANDOM_IV = %d",
ssl_cbc_random_iv);
#else
if(ssl_cbc_random_iv)
infof(data, "WARNING: support for SSL_CBC_RANDOM_IV not compiled in");
#endif
if(SSL_CONN_CONFIG(cipher_list)) {
if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
result = CURLE_SSL_CIPHER;
goto error;
}
}
if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
infof(data, "WARNING: ignoring value of ssl.verifyhost");
/* bypass the default SSL_AuthCertificate() hook in case we do not want to
* verify peer */
if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess)
goto error;
/* not checked yet */
SSL_SET_OPTION_LVALUE(certverifyresult) = 0;
if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess)
goto error;
if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess)
goto error;
{
const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
/* not a fatal error because we are not going to verify the peer */
infof(data, "WARNING: CA certificates failed to load");
else if(rv) {
result = rv;
goto error;
}
}
if(SSL_SET_OPTION(primary.CRLfile)) {
const CURLcode rv = nss_load_crl(SSL_SET_OPTION(primary.CRLfile));
if(rv) {
result = rv;
goto error;
}
infof(data, " CRLfile: %s", SSL_SET_OPTION(primary.CRLfile));
}
if(SSL_SET_OPTION(primary.clientcert)) {
char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert));
if(nickname) {
/* we are not going to use libnsspem.so to read the client cert */
backend->obj_clicert = NULL;
}
else {
CURLcode rv = cert_stuff(data, conn, sockindex,
SSL_SET_OPTION(primary.clientcert),
SSL_SET_OPTION(key));
if(rv) {
/* failf() is already done in cert_stuff() */
result = rv;
goto error;
}
}
/* store the nickname for SelectClientCert() called during handshake */
backend->client_nickname = nickname;
}
else
backend->client_nickname = NULL;
if(SSL_GetClientAuthDataHook(model, SelectClientCert,
(void *)connssl) != SECSuccess) {
result = CURLE_SSL_CERTPROBLEM;
goto error;
}
#ifndef CURL_DISABLE_PROXY
if(conn->proxy_ssl[sockindex].use) {
struct ssl_backend_data *proxy_backend;
proxy_backend = conn->proxy_ssl[sockindex].backend;
DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
DEBUGASSERT(proxy_backend);
DEBUGASSERT(proxy_backend->handle);
nspr_io = proxy_backend->handle;
second_layer = TRUE;
}
#endif
else {
/* wrap OS file descriptor by NSPR's file descriptor abstraction */
nspr_io = PR_ImportTCPSocket(sockfd);
if(!nspr_io)
goto error;
}
/* create our own NSPR I/O layer */
nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
if(!nspr_io_stub) {
if(!second_layer)
PR_Close(nspr_io);
goto error;
}
/* make the per-connection data accessible from NSPR I/O callbacks */
nspr_io_stub->secret = (void *)connssl;
/* push our new layer to the NSPR I/O stack */
if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
if(!second_layer)
PR_Close(nspr_io);
PR_Close(nspr_io_stub);
goto error;
}
/* import our model socket onto the current I/O stack */
backend->handle = SSL_ImportFD(model, nspr_io);
if(!backend->handle) {
if(!second_layer)
PR_Close(nspr_io);
goto error;
}
PR_Close(model); /* We don't need this any more */
model = NULL;
/* This is the password associated with the cert that we're using */
if(SSL_SET_OPTION(key_passwd)) {
SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
}
#ifdef SSL_ENABLE_OCSP_STAPLING
if(SSL_CONN_CONFIG(verifystatus)) {
if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
!= SECSuccess)
goto error;
}
#endif
#ifdef SSL_ENABLE_NPN
if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
? PR_TRUE : PR_FALSE) != SECSuccess)
goto error;
#endif
#ifdef SSL_ENABLE_ALPN
if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
? PR_TRUE : PR_FALSE) != SECSuccess)
goto error;
#endif
#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
if(data->set.ssl.falsestart) {
if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
!= SECSuccess)
goto error;
if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
data) != SECSuccess)
goto error;
}
#endif
#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
int cur = 0;
unsigned char protocols[128];
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif
) {
protocols[cur++] = ALPN_H2_LENGTH;
memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH);
cur += ALPN_H2_LENGTH;
}
#endif
protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
cur += ALPN_HTTP_1_1_LENGTH;
if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess)
goto error;
}
#endif
/* Force handshake on next I/O */
if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
!= SECSuccess)
goto error;
/* propagate hostname to the TLS layer */
if(SSL_SetURL(backend->handle, snihost) != SECSuccess)
goto error;
/* prevent NSS from re-using the session for a different hostname */
if(SSL_SetSockPeerID(backend->handle, snihost) != SECSuccess)
goto error;
return CURLE_OK;
error:
if(model)
PR_Close(model);
return nss_fail_connect(connssl, data, result);
}