diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt
index f126c2983a..90835d02db 100644
--- a/CoreFoundation/CMakeLists.txt
+++ b/CoreFoundation/CMakeLists.txt
@@ -442,6 +442,10 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
     add_compile_definitions($<$<COMPILE_LANGUAGE:C>:NS_CURL_MISSING_MAX_HOST_CONNECTIONS>)
   endif()
 
+  if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.71.0"))
+    add_compile_definitions($<$<COMPILE_LANGUAGE:C>:NS_CURL_MISSING_CURLINFO_SSLCERT_BLOB> $<$<COMPILE_LANGUAGE:C>:NS_CURL_MISSING_CURLINFO_SSLKEY_BLOB>)
+  endif()
+
   if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.84.0"))
     add_compile_definitions($<$<COMPILE_LANGUAGE:C>:NS_CURL_MISSING_CURLINFO_CAINFO>)
   endif()
diff --git a/CoreFoundation/URL.subproj/CFURLSessionInterface.c b/CoreFoundation/URL.subproj/CFURLSessionInterface.c
index 1e6ec24a05..453d069147 100644
--- a/CoreFoundation/URL.subproj/CFURLSessionInterface.c
+++ b/CoreFoundation/URL.subproj/CFURLSessionInterface.c
@@ -111,6 +111,14 @@ CFURLSessionEasyCode CFURLSession_easy_setopt_tc(CFURLSessionEasyHandle _Nonnull
     return MakeEasyCode(curl_easy_setopt(curl,  option.value, a));
 }
 
+CFURLSessionEasyCode CFURLSession_easy_setopt_blob(CFURLSessionEasyHandle _Nonnull curl, CFURLSessionOption option, void *_Nonnull data, size_t len) {
+    struct curl_blob stblob;
+    stblob.data = data;
+    stblob.len = len;
+    stblob.flags = CURL_BLOB_COPY;
+    return MakeEasyCode(curl_easy_setopt(curl,  option.value, &stblob));
+}
+
 CFURLSessionEasyCode CFURLSession_easy_getinfo_long(CFURLSessionEasyHandle _Nonnull curl, CFURLSessionInfo info, long *_Nonnull a) {
     return MakeEasyCode(curl_easy_getinfo(curl, info.value, a));
 }
@@ -366,6 +374,9 @@ CFURLSessionOption const CFURLSessionOptionCOOKIE = { CURLOPT_COOKIE };
 CFURLSessionOption const CFURLSessionOptionHTTPHEADER = { CURLOPT_HTTPHEADER };
 CFURLSessionOption const CFURLSessionOptionHTTPPOST = { CURLOPT_HTTPPOST };
 CFURLSessionOption const CFURLSessionOptionSSLCERT = { CURLOPT_SSLCERT };
+#if !NS_CURL_MISSING_CURLINFO_SSLCERT_BLOB
+CFURLSessionOption const CFURLSessionOptionSSLCERT_BLOB = { CURLOPT_SSLCERT_BLOB };
+#endif
 CFURLSessionOption const CFURLSessionOptionKEYPASSWD = { CURLOPT_KEYPASSWD };
 CFURLSessionOption const CFURLSessionOptionCRLF = { CURLOPT_CRLF };
 CFURLSessionOption const CFURLSessionOptionQUOTE = { CURLOPT_QUOTE };
@@ -419,6 +430,9 @@ CFURLSessionOption const CFURLSessionOptionHTTP_VERSION = { CURLOPT_HTTP_VERSION
 CFURLSessionOption const CFURLSessionOptionFTP_USE_EPSV = { CURLOPT_FTP_USE_EPSV };
 CFURLSessionOption const CFURLSessionOptionSSLCERTTYPE = { CURLOPT_SSLCERTTYPE };
 CFURLSessionOption const CFURLSessionOptionSSLKEY = { CURLOPT_SSLKEY };
+#if !NS_CURL_MISSING_CURLINFO_SSLKEY_BLOB
+CFURLSessionOption const CFURLSessionOptionSSLKEY_BLOB = { CURLOPT_SSLKEY_BLOB };
+#endif
 CFURLSessionOption const CFURLSessionOptionSSLKEYTYPE = { CURLOPT_SSLKEYTYPE };
 CFURLSessionOption const CFURLSessionOptionSSLENGINE = { CURLOPT_SSLENGINE };
 CFURLSessionOption const CFURLSessionOptionSSLENGINE_DEFAULT = { CURLOPT_SSLENGINE_DEFAULT };
diff --git a/CoreFoundation/URL.subproj/CFURLSessionInterface.h b/CoreFoundation/URL.subproj/CFURLSessionInterface.h
index 9856949a7f..5f7894e855 100644
--- a/CoreFoundation/URL.subproj/CFURLSessionInterface.h
+++ b/CoreFoundation/URL.subproj/CFURLSessionInterface.h
@@ -199,6 +199,7 @@ CF_EXPORT CFURLSessionOption const CFURLSessionOptionCOOKIE; // CURLOPT_COOKIE
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionHTTPHEADER; // CURLOPT_HTTPHEADER
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionHTTPPOST; // CURLOPT_HTTPPOST
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLCERT; // CURLOPT_SSLCERT
+CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLCERT_BLOB; // CURLOPT_SSLCERT_BLOB
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionKEYPASSWD; // CURLOPT_KEYPASSWD
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionCRLF; // CURLOPT_CRLF
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionQUOTE; // CURLOPT_QUOTE
@@ -253,6 +254,7 @@ CF_EXPORT CFURLSessionOption const CFURLSessionOptionHTTP_VERSION; // CURLOPT_HT
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionFTP_USE_EPSV; // CURLOPT_FTP_USE_EPSV
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLCERTTYPE; // CURLOPT_SSLCERTTYPE
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLKEY; // CURLOPT_SSLKEY
+CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLKEY_BLOB; // CURLOPT_SSLKEY_BLOB
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLKEYTYPE; // CURLOPT_SSLKEYTYPE
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLENGINE; // CURLOPT_SSLENGINE
 CF_EXPORT CFURLSessionOption const CFURLSessionOptionSSLENGINE_DEFAULT; // CURLOPT_SSLENGINE_DEFAULT
@@ -626,6 +628,7 @@ typedef int (CFURLSessionSeekCallback)(void *_Nullable userp, long long offset,
 CF_EXPORT CFURLSessionEasyCode CFURLSession_easy_setopt_seek(CFURLSessionEasyHandle _Nonnull curl, CFURLSessionOption option, CFURLSessionSeekCallback * _Nullable a);
 typedef int (CFURLSessionTransferInfoCallback)(void *_Nullable userp, long long dltotal, long long dlnow, long long ultotal, long long ulnow);
 CF_EXPORT CFURLSessionEasyCode CFURLSession_easy_setopt_tc(CFURLSessionEasyHandle _Nonnull curl, CFURLSessionOption option, CFURLSessionTransferInfoCallback * _Nullable a);
+CF_EXPORT CFURLSessionEasyCode CFURLSession_easy_setopt_blob(CFURLSessionEasyHandle _Nonnull curl, CFURLSessionOption option, void *_Nonnull data, size_t len);
 
 CF_EXPORT CFURLSessionEasyCode CFURLSession_easy_getinfo_long(CFURLSessionEasyHandle _Nonnull curl, CFURLSessionInfo info, long *_Nonnull a);
 CF_EXPORT CFURLSessionEasyCode CFURLSession_easy_getinfo_double(CFURLSessionEasyHandle _Nonnull curl, CFURLSessionInfo info, double *_Nonnull a);
diff --git a/Sources/FoundationNetworking/CMakeLists.txt b/Sources/FoundationNetworking/CMakeLists.txt
index ebb8dc405b..8ede2195fc 100644
--- a/Sources/FoundationNetworking/CMakeLists.txt
+++ b/Sources/FoundationNetworking/CMakeLists.txt
@@ -16,6 +16,10 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
     add_compile_definitions(NS_CURL_MISSING_MAX_HOST_CONNECTIONS)
   endif()
 
+  if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.71.0"))
+    add_compile_definitions(NS_CURL_MISSING_CURLINFO_SSLCERT_BLOB NS_CURL_MISSING_CURLINFO_SSLKEY_BLOB)
+  endif()
+
   if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.84.0"))
     add_compile_definitions(NS_CURL_MISSING_CURLINFO_CAINFO)
   endif()
diff --git a/Sources/FoundationNetworking/URLCredential.swift b/Sources/FoundationNetworking/URLCredential.swift
index bdb844ba34..edef40b780 100644
--- a/Sources/FoundationNetworking/URLCredential.swift
+++ b/Sources/FoundationNetworking/URLCredential.swift
@@ -40,8 +40,12 @@ extension URLCredential {
     @discussion This class is an immutable object representing an authentication credential.  The actual type of the credential is determined by the constructor called in the categories declared below.
 */
 open class URLCredential : NSObject, NSSecureCoding, NSCopying {
-    private var _user : String
-    private var _password : String
+    private var _user : String?
+    private var _password : String?
+    // _privateClientKey contains the private client key in DER format
+    private var _privateClientKey: Data?
+    // _privateClientCertificate contains the private client certificate in DER format
+    private var _privateClientCertificate: Data?
     private var _persistence : Persistence
     
     /*!
@@ -55,6 +59,25 @@ open class URLCredential : NSObject, NSSecureCoding, NSCopying {
     public init(user: String, password: String, persistence: Persistence) {
         _user = user
         _password = password
+        _privateClientKey = nil
+        _privateClientCertificate = nil
+        _persistence = persistence
+        super.init()
+    }
+
+    /*!
+        @method initWithUser:password:persistence:
+        @abstract Initialize a URLCredential with a user and password
+        @param user the username
+        @param password the password
+        @param persistence enum that says to store per session, permanently or not at all
+        @result The initialized URLCredential
+     */
+    public init(clientKey: Data, clientCertificate: Data, persistence: Persistence) {
+        _user = nil
+        _password = nil
+        _privateClientKey = clientKey
+        _privateClientCertificate = clientCertificate
         _persistence = persistence
         super.init()
     }
@@ -76,24 +99,34 @@ open class URLCredential : NSObject, NSSecureCoding, NSCopying {
         func bridgeString(_ value: NSString) -> String? {
             return String._unconditionallyBridgeFromObjectiveC(value)
         }
-        
-        let encodedUser = aDecoder.decodeObject(forKey: "NS._user") as! NSString
-        self._user = bridgeString(encodedUser)!
-        
-        let encodedPassword = aDecoder.decodeObject(forKey: "NS._password") as! NSString
-        self._password = bridgeString(encodedPassword)!
-        
-        let encodedPersistence = aDecoder.decodeObject(forKey: "NS._persistence") as! NSNumber
-        self._persistence = Persistence(rawValue: encodedPersistence.uintValue)!
+
+        if let encodedUser = aDecoder.decodeObject(forKey: "NS._user") as? NSString {
+            self._user = bridgeString(encodedUser)!
+        }
+
+        if let encodedPassword = aDecoder.decodeObject(forKey: "NS._password") as? NSString {
+            self._password = bridgeString(encodedPassword)!
+        }
+
+        if let encodedPersistence = aDecoder.decodeObject(forKey: "NS._persistence") as? NSNumber {
+            self._persistence = Persistence(rawValue: encodedPersistence.uintValue)!
+        } else {
+            self._persistence = Persistence.none
+        }
     }
     
     open func encode(with aCoder: NSCoder) {
         guard aCoder.allowsKeyedCoding else {
             preconditionFailure("Unkeyed coding is unsupported.")
         }
-        
-        aCoder.encode(self._user._bridgeToObjectiveC(), forKey: "NS._user")
-        aCoder.encode(self._password._bridgeToObjectiveC(), forKey: "NS._password")
+
+        if let user = self._user {
+            aCoder.encode(user._bridgeToObjectiveC(), forKey: "NS._user")
+        }
+        if let password = self._password {
+            aCoder.encode(password._bridgeToObjectiveC(), forKey: "NS._password")
+        }
+
         aCoder.encode(self._persistence.rawValue._bridgeToObjectiveC(), forKey: "NS._persistence")
     }
     
@@ -141,6 +174,20 @@ open class URLCredential : NSObject, NSSecureCoding, NSCopying {
      */
     open var password: String? { return _password }
 
+    /*!
+        @method privateClientKey
+        @abstract Get the private client key
+        @result The private key binary blob
+     */
+    open var privateClientKey: Data? { return _privateClientKey }
+
+    /*!
+        @method privateClientCertificate
+        @abstract Get the private client key
+        @result The private key binary blob
+     */
+    open var privateClientCertificate: Data? { return _privateClientCertificate }
+
     /*!
         @method hasPassword
         @abstract Find out if this credential has a password, without trying to get it
@@ -152,6 +199,6 @@ open class URLCredential : NSObject, NSSecureCoding, NSCopying {
      */
     open var hasPassword: Bool {
         // Currently no support for SecTrust/SecIdentity, always return true
-        return true
+        return _password != nil
     }
 }
diff --git a/Sources/FoundationNetworking/URLSession/Configuration.swift b/Sources/FoundationNetworking/URLSession/Configuration.swift
index 7b3996e2e8..5260cbd147 100644
--- a/Sources/FoundationNetworking/URLSession/Configuration.swift
+++ b/Sources/FoundationNetworking/URLSession/Configuration.swift
@@ -78,6 +78,9 @@ internal extension URLSession {
         let shouldUseExtendedBackgroundIdleMode: Bool
         
         let protocolClasses: [AnyClass]?
+
+        /// The credentials to use for connecting to servers
+        let clientCredential: URLCredential?
     }
 }
 internal extension URLSession._Configuration {
@@ -100,6 +103,7 @@ internal extension URLSession._Configuration {
         urlCache = config.urlCache
         shouldUseExtendedBackgroundIdleMode = config.shouldUseExtendedBackgroundIdleMode
         protocolClasses = config.protocolClasses
+        clientCredential = config.clientCredential
     }
 }
 
diff --git a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift
index abf6623435..6dfc0a9ba5 100644
--- a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift
+++ b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift
@@ -328,7 +328,14 @@ internal class _HTTPURLProtocol: _NativeProtocol {
         }
         let session = task?.session as! URLSession
         let _config = session._configuration
-        easyHandle.set(sessionConfig: _config)
+        do {
+            try easyHandle.set(sessionConfig: _config)
+        } catch {
+            self.internalState = .transferFailed
+            let nsError = error as? NSError ?? NSError(domain: NSURLErrorDomain, code: NSURLErrorUserAuthenticationRequired)
+            failWith(error: nsError, request: request)
+            return
+        }
         easyHandle.setAllowedProtocolsToHTTPAndHTTPS()
         easyHandle.set(preferredReceiveBufferSize: Int.max)
         do {
diff --git a/Sources/FoundationNetworking/URLSession/URLSessionConfiguration.swift b/Sources/FoundationNetworking/URLSession/URLSessionConfiguration.swift
index 1282b70135..348847f1d3 100644
--- a/Sources/FoundationNetworking/URLSession/URLSessionConfiguration.swift
+++ b/Sources/FoundationNetworking/URLSession/URLSessionConfiguration.swift
@@ -75,9 +75,10 @@ open class URLSessionConfiguration : NSObject, NSCopying {
                   urlCredentialStorage: .shared,
                   urlCache: .shared,
                   shouldUseExtendedBackgroundIdleMode: false,
-                  protocolClasses: [_HTTPURLProtocol.self, _FTPURLProtocol.self, _WebSocketURLProtocol.self])
+                  protocolClasses: [_HTTPURLProtocol.self, _FTPURLProtocol.self, _WebSocketURLProtocol.self],
+                  clientCredential: nil)
     }
-    
+
     private init(identifier: String?,
                  requestCachePolicy: URLRequest.CachePolicy,
                  timeoutIntervalForRequest: TimeInterval,
@@ -95,7 +96,8 @@ open class URLSessionConfiguration : NSObject, NSCopying {
                  urlCredentialStorage: URLCredentialStorage?,
                  urlCache: URLCache?,
                  shouldUseExtendedBackgroundIdleMode: Bool,
-                 protocolClasses: [AnyClass]?)
+                 protocolClasses: [AnyClass]?,
+                 clientCredential: URLCredential?)
     {
         self.identifier = identifier
         self.requestCachePolicy = requestCachePolicy
@@ -115,6 +117,7 @@ open class URLSessionConfiguration : NSObject, NSCopying {
         self.urlCache = urlCache
         self.shouldUseExtendedBackgroundIdleMode = shouldUseExtendedBackgroundIdleMode
         self.protocolClasses = protocolClasses
+        self.clientCredential = clientCredential
     }
     
     open override func copy() -> Any {
@@ -140,7 +143,8 @@ open class URLSessionConfiguration : NSObject, NSCopying {
             urlCredentialStorage: urlCredentialStorage,
             urlCache: urlCache,
             shouldUseExtendedBackgroundIdleMode: shouldUseExtendedBackgroundIdleMode,
-            protocolClasses: protocolClasses)
+            protocolClasses: protocolClasses,
+            clientCredential: clientCredential)
     }
     
     open class var `default`: URLSessionConfiguration {
@@ -258,6 +262,8 @@ open class URLSessionConfiguration : NSObject, NSCopying {
      @available(*, unavailable, message: "Not available on non-Darwin platforms")
      open var multipathServiceType: URLSessionConfiguration.MultipathServiceType { NSUnsupported() }
 
+    /* Optional client credential to be used when connecting to servers */
+    open var clientCredential: URLCredential?
 }
 
 @available(*, unavailable, message: "Not available on non-Darwin platforms")
diff --git a/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift b/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift
index 45cd8cae7e..b805895b8c 100644
--- a/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift
+++ b/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift
@@ -178,8 +178,55 @@ extension _EasyHandle {
         }
     }
 
-    func set(sessionConfig config: URLSession._Configuration) {
+    func set(sessionConfig config: URLSession._Configuration) throws {
         _config = config
+        if let c = _config, let clientCredential = c.clientCredential {
+            // For TLS client certificate authentication
+            if var privateClientKey = clientCredential.privateClientKey,
+               var privateClientCertificate = clientCredential.privateClientCertificate {
+                // Key and certificate are expected to be in DER format
+                "DER".withCString {
+                    let mutablePointer = UnsafeMutablePointer(mutating: $0)
+                    try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionSSLKEYTYPE, mutablePointer).asError()
+                    try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionSSLCERTTYPE, mutablePointer).asError()
+                }
+
+#if !NS_CURL_MISSING_CURLINFO_SSLKEY_BLOB
+                privateClientKey.withUnsafeMutableBytes {
+                    if let baseAddress = $0.baseAddress {
+                        try! CFURLSession_easy_setopt_blob(rawHandle, CFURLSessionOptionSSLKEY_BLOB,
+                            baseAddress, $0.count).asError()
+                    }
+                }
+#endif // !NS_CURL_MISSING_CURLINFO_SSLKEY_BLOB
+
+#if !NS_CURL_MISSING_CURLINFO_SSLCERT_BLOB
+                privateClientCertificate.withUnsafeMutableBytes {
+                    if let baseAddress = $0.baseAddress {
+                        try! CFURLSession_easy_setopt_blob(rawHandle, CFURLSessionOptionSSLCERT_BLOB,
+                            baseAddress, $0.count).asError()
+                    }
+                }
+#endif // !NS_CURL_MISSING_CURLINFO_SSLCERT_BLOB
+            } else if let tlsAuthUsername = clientCredential.user,
+                      let tlsAuthPassword = clientCredential.password {
+                "SRP".withCString {
+                    let mutablePointer = UnsafeMutablePointer(mutating: $0)
+                    try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionTLSAUTH_TYPE, mutablePointer).asError()
+                }
+                tlsAuthUsername.withCString {
+                    let mutablePointer = UnsafeMutablePointer(mutating: $0)
+                    try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionTLSAUTH_USERNAME, mutablePointer).asError()
+                }
+                tlsAuthPassword.withCString {
+                    let mutablePointer = UnsafeMutablePointer(mutating: $0)
+                    try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionTLSAUTH_PASSWORD, mutablePointer).asError()
+                }
+            } else {
+                throw NSError(domain: NSURLErrorDomain, code: NSURLErrorUserAuthenticationRequired,
+                              userInfo: [NSLocalizedDescriptionKey: "Client credentials from URLSessionConfiguration is incomplete."])
+            }
+        }
     }
 
     /// Set the CA bundle path automatically if it isn't set