This took me far too long to find out, and I wasted a lot of time trying to get this to work, but 802.1x EAP-TLS authentication for Cisco phones doesn’t work with Microsoft’s NPS (or at least not easily). This is due to a combination of the way NPS verifies certificates, and the certificates that Call Manager issues to phones.
Specifically, the certificates (called LSCs) that Call Manager (using the CAPF functionality) issues to phones, are missing the CDP and AIA extensions. For some reason Cisco just didn’t include them. The issue arises when NPS goes to authenticate the phones, because NPS requires that those extensions be set so it can check if the certificate is expired.
Cisco has a bug entry about this here: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCup94684/?reffering_site=dumpcr. Be aware that you need to have an account in order to see this.
I also found this forum post that set me in the right direction: https://supportforums.cisco.com/t5/ip-telephony/802-1x-eap-tls-with-cisco-ip-phone-on-ms-nps/m-p/1768995/highlight/true#M166951
I ended up opening up a support case to see if there was any way to get this to work. They said it might be possible to do this using the default (MIC) certificate that the phones have, but that would be a large hassle to get going if you need to import those into the NPS server. There also was a registry key that could be set that would have it so NPS wouldn’t verify the certificate, but that’s a bit insecure (one of those settings Microsoft says to only use in a lab), and I didn’t want to go that route.
The solution I’ll be looking at next will be another 802.1x server. Cisco’s ISE would be nice, but there is a cost to it, so I’ll first be investigating FreeRADIUS to see how it works.