mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-18 12:39:28 +00:00
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
327 lines
9.8 KiB
C
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);
|
|
}
|