Networking

RSS for tag

Explore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.

Networking Documentation

Posts under Networking subtopic

Post

Replies

Boosts

Views

Activity

Unable to update app with PacketTunnelProvider running
Hi there, I am working on an app that configures a PacketTunnelProvider to establish a VPN connection. Unfortunately, while a VPN connection is established, I am unable to update the app via testflight. Downloading other app updates works fine. I noticed that after I receive the alert that updating failed, the vpn badge appears at the top of my screen (the same ux that occurs when the connection is first established). So it's almost like it tried to close the tunnel, and seeing that the app update failed it restablishes the tunnel. I am unsure of why I would not be able to update my app. Maybe stopTunnel is not being called with NEProviderStopReason.appUpdate?
1
0
62
Jun ’25
Network Extension Framework Entitlements
At WWDC 2015 Apple announced two major enhancements to the Network Extension framework: Network Extension providers — These are app extensions that let you insert your code at various points within the networking stack, including: Packet tunnels via NEPacketTunnelProvider App proxies via NEAppProxyProvider Content filters via NEFilterDataProvider and NEFilterControlProvider Hotspot Helper (NEHotspotHelper) — This allows you to create an app that assists the user in navigating a hotspot (a Wi-Fi network where the user must interact with the network in order to get access to the wider Internet). Originally, using any of these facilities required authorisation from Apple. Specifically, you had to apply for, and be granted access to, a managed capability. In Nov 2016 this policy changed for Network Extension providers. Any developer can now use the Network Extension provider capability like they would any other capability. There is one exception to this rule: Network Extension app push providers, introduced by iOS 14 in 2020, still requires that Apple authorise the use of a managed capability. To apply for that, follow the link in Local push connectivity. Also, the situation with Hotspot Helpers remains the same: Using a Hotspot Helper, requires that Apple authorise that use via a managed capability. To apply for that, follow the link in Hotspot helper. IMPORTANT Pay attention to this quote from the documentation: NEHotspotHelper is only useful for hotspot integration. There are both technical and business restrictions that prevent it from being used for other tasks, such as accessory integration or Wi-Fi based location. The rest of this document answers some frequently asked questions about the Nov 2016 change. #1 — Has there been any change to the OS itself? No, this change only affects the process by which you get the capabilities you need in order to use existing Network Extension framework facilities. Previously these were managed capabilities, meaning their use was authorised by Apple. Now, except for app push providers and Hotspot Helper, you can enable the necessary capabilities using Xcode’s Signing & Capabilities editor or the Developer website. IMPORTANT Some Network Extension providers have other restrictions on their use. For example, a content filter can only be used on a supervised device. These restrictions are unchanged. See TN3134 Network Extension provider deployment for the details. #2 — How exactly do I enable the Network Extension provider capability? In the Signing & Capabilities editor, add the Network Extensions capability and then check the box that matches the provider you’re creating. In the Certificates, Identifiers & Profiles section of the Developer website, when you add or edit an App ID, you’ll see a new capability listed, Network Extensions. Enable that capability in your App ID and then regenerate the provisioning profiles based on that App ID. A newly generated profile will include the com.apple.developer.networking.networkextension entitlement in its allowlist; this is an array with an entry for each of the supported Network Extension providers. To confirm that this is present, dump the profile as shown below. $ security cms -D -i NETest.mobileprovision … <plist version="1.0"> <dict> … <key>Entitlements</key> <dict> <key>com.apple.developer.networking.networkextension</key> <array> <string>packet-tunnel-provider</string> <string>content-filter-provider</string> <string>app-proxy-provider</string> … and so on … </array> … </dict> … </dict> </plist> #3 — I normally use Xcode’s Signing & Capabilities editor to manage my entitlements. Do I have to use the Developer website for this? No. Xcode 11 and later support this capability in the Signing & Capabilities tab of the target editor (r. 28568128 ). #4 — Can I still use Xcode’s “Automatically manage signing” option? Yes. Once you modify your App ID to add the Network Extension provider capability, Xcode’s automatic code signing support will include the entitlement in the allowlist of any profiles that it generates based on that App ID. #5 — What should I do if I previously applied for the Network Extension provider managed capability and I’m still waiting for a reply? Consider your current application cancelled, and use the new process described above. #6 — What should I do if I previously applied for the Hotspot Helper managed capability and I’m still waiting for a reply? Apple will continue to process Hotspot Helper managed capability requests and respond to you in due course. #7 — What if I previously applied for both Network Extension provider and Hotspot Helper managed capabilities? Apple will ignore your request for the Network Extension provider managed capability and process it as if you’d only asked for the Hotspot Helper managed capability. #8 — On the Mac, can Developer ID apps host Network Extension providers? Yes, but there are some caveats: This only works on macOS 10.15 or later. Your Network Extension provider must be packaged as a system extension, not an app extension. You must use the *-systemextension values for the Network Extension entitlement (com.apple.developer.networking.networkextension). For more on this, see Exporting a Developer ID Network Extension. #9 — After moving to the new process, my app no longer has access to the com.apple.managed.vpn.shared keychain access group. How can I regain that access? Access to this keychain access group requires another managed capability. If you need that, please open a DTS code-level support request and we’ll take things from there. IMPORTANT This capability is only necessary if your VPN supports configuration via a configuration profile and needs to access credentials from that profile (as discussed in the Profile Configuration section of the NETunnelProviderManager Reference). Many VPN apps don’t need this facility. If you were previously granted the Network Extension managed capability (via the process in place before Nov 2016), make sure you mention that; restoring your access to the com.apple.managed.vpn.shared keychain access group should be straightforward in that case. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Revision History 2025-11-11 Removed the discussion of TSI assets because those are no longer a thing. 2025-09-12 Adopted the code-level support request terminology. Made other minor editorial changes. 2023-01-11 Added a discussion of Network Extension app push providers. Added a link to Exporting a Developer ID Network Extension. Added a link to TN3134. Made significant editorial changes. 2020-02-27 Fixed the formatting. Updated FAQ#3. Made minor editorial changes. 2020-02-16 Updated FAQ#8 to account for recent changes. Updated FAQ#3 to account for recent Xcode changes. Made other editorial changes. 2016-01-25 Added FAQ#9. 2016-01-6 Added FAQ#8. 2016-11-11 Added FAQ#5, FAQ#6 and FAQ#7. 2016-11-11 First posted.
0
0
23k
Nov ’25
iPhone App 进行网络请求的时候出错,报错信息为:未能完成该操作。设备上无剩余空间
1、已经检查过手机的存储空间,还有一百多G的空间。app端进行网络接口情况的时候报错了,报错信息如下: Error : Error Domain=NSPOSIXErrorDomain Code=28 "No space left on device" UserInfo={_NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <7DB1CBFD-B9BE-422D-9C9A-78D8FC04DC1B>.<76>, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=28, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <7DB1CBFD-B9BE-422D-9C9A-78D8FC04DC1B>.<76>" ), _NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: pdp_ip0[lte], ipv4, ipv6, dns, expensive, estimated upload: 65536Bps, uses cell} 2、手机型号是iPhone 15 Plus,iOS 17.6.1
2
0
387
Jun ’25
Connecting to a service found by Bonjour isn't working.
I'm using NWBrowser to search for a server that I hosted. The browser does find my service but when it tries to connect to it, it gets stuck in the preparing phase in NWConnection.stateUpdateHandler. When I hardcode the local IP address of my computer (where the server is hosted) into NWConnection it works perfectly fine and is able to connect. When it gets stuck in the preparing phase, it gives me the warnings and error messages in the image below. You can also see that the service name is correct and it is found. I have tried _http._tcp and _ssh._tcp types and neither work. This is what my code looks like: func findServerAndConnect(port: UInt16) { print("Searching for server...") let browser = NWBrowser(for: .bonjour(type: "_ssh._tcp", domain: "local."), using: .tcp) browser.browseResultsChangedHandler = { results, _ in print("Found results: \(results)") for result in results { if case let NWEndpoint.service(name, type_, domain, interface) = result.endpoint { if name == "PocketPadServer" { print("Found service: \(name) of type \(type_) in domain \(domain) on interface \(interface)") // Construct the full service name, including type and domain let fullServiceName = "\(name).\(type_).\(domain)" print("Full service name: \(fullServiceName), \(result.endpoint)") self.connect(to: result.endpoint, port: port) browser.cancel() break } } } } browser.start(queue: .main) } func connect(to endpoint: NWEndpoint, port: UInt16) { print("Connecting to \(endpoint) on port \(port)...") // endpoint = NWEndpoint( let tcpParams = NWProtocolTCP.Options() tcpParams.enableFastOpen = true tcpParams.keepaliveIdle = 2 let params = NWParameters(tls: nil, tcp: tcpParams) params.includePeerToPeer = true // connection = NWConnection(host: NWEndpoint.Host("xx.xxx.xxx.xxx"), port: NWEndpoint.Port(3000), using: params) connection = NWConnection(to: endpoint, using: params) connection?.pathUpdateHandler = { path in print("Connection path update: \(path)") if path.status == .satisfied { print("Connection path is satisfied") } else { print("Connection path is not satisfied: \(path.status)") } } connection?.stateUpdateHandler = { newState in DispatchQueue.main.async { switch newState { case .ready: print("Connected to server") self.pairing = true self.receiveMessage() case .failed(let error): print("Connection failed: \(error)") self.isConnected = false case .waiting(let error): print("Waiting for connection... \(error)") self.isConnected = false case .cancelled: print("Connection cancelled") self.isConnected = false case .preparing: print("Preparing connection...") self.isConnected = false default: print("Connection state changed: \(newState)") break } } } connection?.start(queue: .main) }
4
0
158
Apr ’25
Question Regarding peekOutboundBytes Limit in NEFilterDataProvider When Using SMB
Dear Apple Developer Technical Support, I am currently developing a macOS network filtering solution using NetworkExtension with NEFilterDataProvider. During implementation of the handleOutboundData logic, we are using the following verdict: NEFilterNewFlowVerdict.filterDataVerdict( withFilterInbound: true, peekInboundBytes: InboundPeekBytes, filterOutbound: true, peekOutboundBytes: OutboundPeekBytes ) However, we have encountered an issue when SMB traffic is involved. When SMB protocol communication occurs, the network connection occasionally becomes unresponsive or appears to stall when peekOutboundBytes is set to a large value. Through testing, we observed the following behavior: On some systems, reducing the peekOutboundBytes value allows SMB communication to proceed normally. On other systems, even relatively small values can still cause the SMB connection to stall. This behavior appears inconsistent across different macOS environments. Because of this, we would like to clarify the following: Is there a documented or recommended maximum value for peekOutboundBytes when using NEFilterNewFlowVerdict.filterDataVerdict? Are there any internal limits or constraints within NetworkExtension that could cause SMB traffic to stall when the peek buffer size is too large? Are there best practices for selecting appropriate peekInboundBytes / peekOutboundBytes values when filtering high-throughput protocols such as SMB? If necessary, we can provide additional information such as macOS version, test environment details, and logs. Thank you for your assistance. Best regards, sangho
1
0
49
1w
in-addr.arpa default search domains
Hi, I observed some unexpected behavior and hope that someone can enlighten me as to what this is about: mDNSResponder prepends IP / network based default search domains that are checked before any other search domain. E.g. 0.1.168.192.in-addr.arpa. would be used for an interface with an address in the the 192.168.1.0/24 subnet. This is done for any configured non-link-local IP address. I tried to find any mention of an approach like this in RFCs but couldn't spot anything. Please note that this is indeed a search domain and different from reverse-DNS lookups. Example output of tcpdump for ping devtest: 10:02:13.850802 IP (tos 0x0, ttl 64, id 43461, offset 0, flags [none], proto UDP (17), length 92) 192.168.1.2.52319 &gt; 192.168.1.1.53: 54890+ [1au] A? devtest.0.1.168.192.in-addr.arpa. (64) I was able to identify the code that adds those default IP subnet based search domains but failed to spot any indication as to what this is about: https://github.com/apple-oss-distributions/mDNSResponder/blob/d5029b5/mDNSMacOSX/mDNSMacOSX.c#L4171-L4211 Does anyone here have an ideas as to what this might be about?
1
0
772
Apr ’25
Thread topology data: no API path for parent-child relationships
I'm building a HomeKit app that discovers Thread devices and visualizes the mesh topology. I can detect device roles (Router vs End Device via characteristic 0x0703) and identify Border Routers (via _meshcop._udp), but I cannot determine which Router is the parent of a given End Device. Any Thread device can act as a Router (a Nanoleaf bulb, an Eve plug, not just HomePods), and End Devices attach to these Routers as children. That parent-child relationship is what I'm trying to map, but there's no RLOC16, neighbor table, or parent identifier exposed through any available API. I've tested every path I can find. Here's what I've tried on a network with 44 Thread devices and 6 Border Routers: What works (partially) HAP Thread Management Service (0x0701) gives me the device role from characteristic 0x0703, the OpenThread version from 0x0706, and node capabilities from 0x0702. That's the complete set of characteristics on that service. None of them contain RLOC16, parent Router, or neighbor data. This service also only exists on HAP-native Thread devices. My 20 Matter-over-Thread devices (Aqara, Eve Door, SmartWings, Onvis S4) don't have it at all. MeshCoP Bonjour (_meshcop._udp) identifies Border Routers and the network name/Extended PAN ID. No topology data about other mesh nodes. What doesn't work ThreadNetwork framework (THClient) - retrieveAllCredentials() returns error Code 3 because the app can't access credentials stored by Apple Home. Even if it worked, THCredentials only contains network config (name, PAN ID, channel), not topology. Direct CoAP queries - Border Routers don't route traffic from WiFi to Thread management ports. Mesh-local addresses aren't reachable. No Thread NWInterface in Network.framework. Network.framework - No visibility into the Thread mesh from the WiFi side. The only remaining path I can see (but it's not practical) Matter cluster 0x0035 (Thread Network Diagnostics) appears to have exactly what I need: RLOC16, NeighborTable with isChild boolean, RouteTable. I haven't implemented this because it requires commissioning each device individually onto my app's own Matter fabric via Multi-Admin. That's 21 separate user-initiated pairing actions on my network. I can't ask end users to do that. The core issue Every Thread Router (whether it's a HomePod acting as a Border Router or a Nanoleaf bulb acting as a mesh Router) knows its own children and neighbors. The Border Routers also maintain route tables covering the mesh backbone. This data exists on the user's own devices but none of it is exposed to third-party apps. Even something minimal would help. HMAccessory already exposes matterNodeID as a cross-protocol identifier. Exposing RLOC16 the same way would be enough, since parent-child relationships are encoded in the address itself (ParentRLOC = ChildRLOC & 0xFC00). Has anyone found another approach I'm missing? Thanks in advance for any pointers.
1
0
105
1w
Content filtering
Hello team, Would this mean that content filters intended for all browsing can only be implemented for managed devices using MDM? My goal would be to create a content filtering app for all users, regardless of if their device is managed/supervised. thanks.
1
0
101
Jan ’26
WiFi Aware connection cannot be established when both peers publish and subscribe
It works when one device is only a publisher and the other is only a subscriber. However, when both devices act as both publisher and subscriber simultaneously—which Apple’s documentation (https://developer.apple.com/documentation/wifiaware/adopting-wi-fi-aware#Declare-services) indicates is valid—the connection never establishes. After timing out, both NetworkListener and NetworkBrowser transition to the failed state. This appears to be a race condition in Network framework. Task.detached { try await NetworkListener( for: .wifiAware( .connecting( to: .myService, from: .allPairedDevices, datapath: .defaults ) ), using: .parameters { Coder( sending: ..., receiving: ..., using: NetworkJSONCoder() ) { TCP() } } ).run { connection in await self.add(connection: connection) } } Task.detached { try await NetworkBrowser( for: .wifiAware( .connecting( to: .allPairedDevices, from: .myService ) ), using: .tcp ).run { endpoints in for endpoint in endpoints { await self.connect(to: endpoint) } } }
1
0
117
Jan ’26
VPN Stuck at connecting
Hello, I’ve run into some strange behavior with the macOS System Extension using a Packet Tunnel. The issue showed up after the device went to sleep while the VPN was running. When I woke the computer, the VPN tried to reconnect but never succeeded — it just stayed stuck in the “connecting” state. I was able to turn the VPN off, but every attempt to turn it back on failed and got stuck at “connecting” again. Even removing the VPN configuration from Settings didn’t help. The only thing that worked was disabling the system extension completely. While checking the logs, I noticed thousands of identical log messages appearing within just a few seconds: nesessionmanager(562) deny(1) system-fsctl (_IO "h" 47) 17:11:52.481498+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5454 com.apple.networkextension 17:11:52.481568+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5454 com.apple.networkextension 17:11:52.481580+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5454 com.apple.networkextension 17:11:52.481587+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5454 com.apple.networkextension 17:11:52.481646+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5446 com.apple.networkextension 17:11:52.481664+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5446 com.apple.networkextension 17:11:52.481671+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5446 com.apple.networkextension 17:11:52.481676+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5446 com.apple.networkextension 17:11:52.481682+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5446 com.apple.networkextension 17:11:52.481687+0200 NESMVPNSession[Primary Tunnel:Secure DNS: got On Demand start message from pid 5446 com.apple.networkextension After the burst of these repeated messages, I started seeing logs like the following: 17:11:52.481759+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from Spotify Helper[69038] com.apple.networkextension 17:11:52.481790+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from Spotify Helper[69038]: session in state connecting com.apple.networkextension 17:11:52.481949+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from Spotify Helper[69038] com.apple.networkextension 17:11:52.481966+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from Spotify Helper[69038]: session in state connecting com.apple.networkextension 17:11:52.481986+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from Spotify Helper[69038] com.apple.networkextension 17:11:52.481992+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from Spotify Helper[69038]: session in state connecting com.apple.networkextension 17:11:52.482003+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from Spotify Helper[69038] com.apple.networkextension 17:11:52.482011+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from Spotify Helper[69038]: session in state connecting com.apple.networkextension 17:11:52.482022+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from Spotify Helper[69038] com.apple.networkextension 17:11:52.482028+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from Spotify Helper[69038]: session in state connecting com.apple.networkextension 17:11:52.482039+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from Spotify Helper[69038] com.apple.networkextension 17:11:52.482049+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from Spotify Helper[69038]: session in state connecting com.apple.networkextension 17:11:52.482060+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from Slack Helper[84828] com.apple.networkextension 17:11:52.482069+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from Slack Helper[84828]: session in state connecting com.apple.networkextension 17:11:52.482079+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Received a start command from sharingd[764] com.apple.networkextension 17:11:52.482086+0200 NESMVPNSession[Primary Tunnel:Secure DNS: Skip a start command from sharingd[764]: session in state connecting com.apple.networkextension It is clear that the connection is in a loop of submitting request to start and then failing. This problem occured only after sleep on macOS 26.0 and 15.6. This issue only occured after the system woke up from sleep. macOS 15.6 and 26.0. Is this a known problem, and how should I go about troubleshooting or resolving it?
3
0
165
Oct ’25
NEHotspotHelper API
For our outdoor power supply company that builds public WiFi networks at camping sites, we want to implement the following features in our app: Scan surrounding WiFi networks When detecting specific public WiFi SSIDs, provide users with corresponding passwords Automatically connect to those WiFi networks Regarding the NEHotspotHelper API permission application, when I clicked on https://developer.apple.com/contact/request/network-extension, it redirected me to https://developer.apple.com/unauthorized/. I'm not sure where to properly apply for this permission now.
1
0
35
May ’25
TLS for App Developers
Transport Layer Security (TLS) is the most important security protocol on the Internet today. Most notably, TLS puts the S into HTTPS, adding security to the otherwise insecure HTTP protocol. IMPORTANT TLS is the successor to the Secure Sockets Layer (SSL) protocol. SSL is no longer considered secure and it’s now rarely used in practice, although many folks still say SSL when they mean TLS. TLS is a complex protocol. Much of that complexity is hidden from app developers but there are places where it’s important to understand specific details of the protocol in order to meet your requirements. This post explains the fundamentals of TLS, concentrating on the issues that most often confuse app developers. Note The focus of this is TLS-PKI, where PKI stands for public key infrastructure. This is the standard TLS as deployed on the wider Internet. There’s another flavour of TLS, TLS-PSK, where PSK stands for pre-shared key. This has a variety of uses, but an Apple platforms we most commonly see it with local traffic, for example, to talk to a Wi-Fi based accessory. For more on how to use TLS, both TLS-PKI and TLS-PSK, in a local context, see TLS For Accessory Developers. Server Certificates For standard TLS to work the server must have a digital identity, that is, the combination of a certificate and the private key matching the public key embedded in that certificate. TLS Crypto Magic™ ensures that: The client gets a copy of the server’s certificate. The client knows that the server holds the private key matching the public key in that certificate. In a typical TLS handshake the server passes the client a list of certificates, where item 0 is the server’s certificate (the leaf certificate), item N is (optionally) the certificate of the certificate authority that ultimately issued that certificate (the root certificate), and items 1 through N-1 are any intermediate certificates required to build a cryptographic chain of trust from 0 to N. Note The cryptographic chain of trust is established by means of digital signatures. Certificate X in the chain is issued by certificate X+1. The owner of certificate X+1 uses their private key to digitally sign certificate X. The client verifies this signature using the public key embedded in certificate X+1. Eventually this chain terminates in a trusted anchor, that is, a certificate that the client trusts by default. Typically this anchor is a self-signed root certificate from a certificate authority. Note Item N is optional for reasons I’ll explain below. Also, the list of intermediate certificates may be empty (in the case where the root certificate directly issued the leaf certificate) but that’s uncommon for servers in the real world. Once the client gets the server’s certificate, it evaluates trust on that certificate to confirm that it’s talking to the right server. There are three levels of trust evaluation here: Basic X.509 trust evaluation checks that there’s a cryptographic chain of trust from the leaf through the intermediates to a trusted root certificate. The client has a set of trusted root certificates built in (these are from well-known certificate authorities, or CAs), and a site admin can add more via a configuration profile. This step also checks that none of the certificates have expired, and various other more technical criteria (like the Basic Constraints extension). Note This explains why the server does not have to include the root certificate in the list of certificates it passes to the client; the client has to have the root certificate installed if trust evaluation is to succeed. In addition, TLS trust evaluation (per RFC 2818) checks that the DNS name that you connected to matches the DNS name in the certificate. Specifically, the DNS name must be listed in the Subject Alternative Name extension. Note The Subject Alternative Name extension can also contain IP addresses, although that’s a much less well-trodden path. Also, historically it was common to accept DNS names in the Common Name element of the Subject but that is no longer the case on Apple platforms. App Transport Security (ATS) adds its own security checks. Basic X.509 and TLS trust evaluation are done for all TLS connections. ATS is only done on TLS connections made by URLSession and things layered on top URLSession (like WKWebView). In many situations you can override trust evaluation; for details, see Technote 2232 HTTPS Server Trust Evaluation). Such overrides can either tighten or loosen security. For example: You might tighten security by checking that the server certificate was issued by a specific CA. That way, if someone manages to convince a poorly-managed CA to issue them a certificate for your server, you can detect that and fail. You might loosen security by adding your own CA’s root certificate as a trusted anchor. IMPORTANT If you rely on loosened security you have to disable ATS. If you leave ATS enabled, it requires that the default server trust evaluation succeeds regardless of any customisations you do. Mutual TLS The previous section discusses server trust evaluation, which is required for all standard TLS connections. That process describes how the client decides whether to trust the server. Mutual TLS (mTLS) is the opposite of that, that is, it’s the process by which the server decides whether to trust the client. Note mTLS is commonly called client certificate authentication. I avoid that term because of the ongoing industry-wide confusion between certificates and digital identities. While it’s true that, in mTLS, the server authenticates the client certificate, to set this up on the client you need a digital identity, not a certificate. mTLS authentication is optional. The server must request a certificate from the client and the client may choose to supply one or not (although if the server requests a certificate and the client doesn’t supply one it’s likely that the server will then fail the connection). At the TLS protocol level this works much like it does with the server certificate. For the client to provide this certificate it must apply a digital identity, known as the client identity, to the connection. TLS Crypto Magic™ assures the server that, if it gets a certificate from the client, the client holds the private key associated with that certificate. Where things diverge is in trust evaluation. Trust evaluation of the client certificate is done on the server, and the server uses its own rules to decided whether to trust a specific client certificate. For example: Some servers do basic X.509 trust evaluation and then check that the chain of trust leads to one specific root certificate; that is, a client is trusted if it holds a digital identity whose certificate was issued by a specific CA. Some servers just check the certificate against a list of known trusted client certificates. When the client sends its certificate to the server it actually sends a list of certificates, much as I’ve described above for the server’s certificates. In many cases the client only needs to send item 0, that is, its leaf certificate. That’s because: The server already has the intermediate certificates required to build a chain of trust from that leaf to its root. There’s no point sending the root, as I discussed above in the context of server trust evaluation. However, there are no hard and fast rules here; the server does its client trust evaluation using its own internal logic, and it’s possible that this logic might require the client to present intermediates, or indeed present the root certificate even though it’s typically redundant. If you have problems with this, you’ll have to ask the folks running the server to explain its requirements. Note If you need to send additional certificates to the server, pass them to the certificates parameter of the method you use to create your URLCredential (typically init(identity:certificates:persistence:)). One thing that bears repeating is that trust evaluation of the client certificate is done on the server, not the client. The client doesn’t care whether the client certificate is trusted or not. Rather, it simply passes that certificate the server and it’s up to the server to make that decision. When a server requests a certificate from the client, it may supply a list of acceptable certificate authorities [1]. Safari uses this to filter the list of client identities it presents to the user. If you are building an HTTPS server and find that Safari doesn’t show the expected client identity, make sure you have this configured correctly. If you’re building an iOS app and want to implement a filter like Safari’s, get this list using: The distinguishedNames property, if you’re using URLSession The sec_protocol_metadata_access_distinguished_names routine, if you’re using Network framework [1] See the certificate_authorities field in Section 7.4.4 of RFC 5246, and equivalent features in other TLS versions. Self-Signed Certificates Self-signed certificates are an ongoing source of problems with TLS. There’s only one unequivocally correct place to use a self-signed certificate: the trusted anchor provided by a certificate authority. One place where a self-signed certificate might make sense is in a local environment, that is, securing a connection between peers without any centralised infrastructure. However, depending on the specific circumstances there may be a better option. TLS For Accessory Developers discusses this topic in detail. Finally, it’s common for folks to use self-signed certificates for testing. I’m not a fan of that approach. Rather, I recommend the approach described in QA1948 HTTPS and Test Servers. For advice on how to set that up using just your Mac, see TN2326 Creating Certificates for TLS Testing. TLS Standards RFC 6101 The Secure Sockets Layer (SSL) Protocol Version 3.0 (historic) RFC 2246 The TLS Protocol Version 1.0 RFC 4346 The Transport Layer Security (TLS) Protocol Version 1.1 RFC 5246 The Transport Layer Security (TLS) Protocol Version 1.2 RFC 8446 The Transport Layer Security (TLS) Protocol Version 1.3 RFC 4347 Datagram Transport Layer Security RFC 6347 Datagram Transport Layer Security Version 1.2 RFC 9147 The Datagram Transport Layer Security (DTLS) Protocol Version 1.3 Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Revision History: 2025-11-21 Clearly defined the terms TLS-PKI and TLS-PSK. 2024-03-19 Adopted the term mutual TLS in preference to client certificate authentication throughout, because the latter feeds into the ongoing certificate versus digital identity confusion. Defined the term client identity. Added the Self-Signed Certificates section. Made other minor editorial changes. 2023-02-28 Added an explanation mTLS acceptable certificate authorities. 2022-12-02 Added links to the DTLS RFCs. 2022-08-24 Added links to the TLS RFCs. Made other minor editorial changes. 2022-06-03 Added a link to TLS For Accessory Developers. 2021-02-26 Fixed the formatting. Clarified that ATS only applies to URLSession. Minor editorial changes. 2020-04-17 Updated the discussion of Subject Alternative Name to account for changes in the 2019 OS releases. Minor editorial updates. 2018-10-29 Minor editorial updates. 2016-11-11 First posted.
0
0
8.3k
Nov ’25
URL Session randomly returns requests extremely slowly!
Hi, I'm experiencing intermittent delays with URLSession where requests take 3-4 seconds to be sent, even though the actual server processing is fast. This happens randomly, maybe 10-20% of requests. The pattern I've noticed is I create my request I send off my request using try await urlSession.data(for: request) My middleware ends up receiving this request 4-7s after its been fired from the client-side The round trip ends up taking 4-7s! This hasn't been reproducible consistently at all on my end. I've also tried ephemeral URLSessions (so recreating the session instead of using .shared so no dead connections, but this doesn't seem to help at all) Completely lost on what to do. Please help!
5
0
311
Nov ’25
TCP socket disconnection with EBROKENPIPE during file copy of signed app bundle
We are developing a client server application using TCP bsd sockets. When our client is connected to the server, copying another client .app bundle from a file server on the same machine (using Finder or terminal using cp), occasionally causes the first client to disconnect. The client receives an EBROKENPIPE error when attempting to write to its socket. In the Console, the following message appears just before the disconnection: necp_socket_find_policy_match: Marking socket in state 258 as defunct This issue seems to occur only when copying an .app bundle signed with the same TeamIdentifier as the running client. Copying arbitrary files or bundles with a different TeamIdentifier does not trigger the problem. We are running on macOS 15.5. The issue appears specific to macOS 15 and was not observed on earlier versions. Any help or pointers would be greatly appreciated!
2
0
214
Jul ’25
Could not delete cookies on IOS18
Hello, I have encountered an issue with an iPhone 15PM with iOS 18.5. The NSHTTPCookieStorage failed to clear cookies, after clearing them, I was still able to retrieve them. However, on the same system NSHTTPCookie *cookie; NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; for (cookie in [storage cookies]) { [storage deleteCookie:cookie]; } NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[[self url] absoluteURL]]; // still able to get cookies,why???
1
0
111
Jun ’25
The network expansion process will become a zombie process and the network will be unusable.
Hi, I developed a network extension program on macOS. I tried to update the program by changing the version number. My update process was to first turn off network filtering via "NEFilterManager.sharedManager.enabled = NO", and then use "[OSSystemExtensionRequest activationRequestForExtension:bundleid queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];" to let the system replace the old network extension program. However, sometimes the old network extension process will become a zombie process like pid=86621 in the figure. As long as the zombie process exists, the network cannot be used. After about 10 minutes, it will be cleared and the network will be available. Restarting Wi-Fi can also clear the zombie process immediately. Why is this? How to avoid this problem?
1
0
111
Jun ’25
CallKit and PushToTalk related changes in iOS 26
Starting in iOS 26, two notable changes have been made to CallKit, LiveCommunicationKit, and the PushToTalk framework: As a diagnostic aid, we're introducing new dialogs to warn apps of voip push related issue, for example when they fail to report a call or when when voip push delivery stops. The specific details of that behavior are still being determined and are likely to change over time, however, the critical point here is that these alerts are only intended to help developers debug and improve their app. Because of that, they're specifically tied to development and TestFlight signed builds, so the alert dialogs will not appear for customers running app store builds. The existing termination/crashes will still occur, but the new warning alerts will not appear. As PushToTalk developers have previously been warned, the last unrestricted PushKit entitlement ("com.apple.developer.pushkit.unrestricted-voip.ptt") has been disabled in the iOS 26 SDK. ALL apps that link against the iOS 26 SDK which receive a voip push through PushKit and which fail to report a call to CallKit will be now be terminated by the system, as the API contract has long specified. __ Kevin Elliott DTS Engineer, CoreOS/Hardware
0
0
926
Jun ’25