diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.X509.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.X509.cs index d50ca014c4e3a..6d39eabdaa180 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.X509.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.X509.cs @@ -20,6 +20,11 @@ internal static partial class AppleCrypto out SafeCFDataHandle cfDataOut, out int pOSStatus); + [DllImport(Libraries.AppleCryptoNative)] + private static extern int AppleCryptoNative_X509GetSubjectSummary( + SafeSecCertificateHandle cert, + out SafeCFStringHandle cfSubjectSummaryOut); + [DllImport(Libraries.AppleCryptoNative)] private static extern int AppleCryptoNative_X509GetPublicKey(SafeSecCertificateHandle cert, out SafeSecKeyRefHandle publicKey, out int pOSStatus); @@ -69,6 +74,31 @@ internal static byte[] X509GetRawData(SafeSecCertificateHandle cert) throw new CryptographicException(); } + internal static string? X509GetSubjectSummary(SafeSecCertificateHandle cert) + { + SafeCFStringHandle subjectSummary; + + int ret = AppleCryptoNative_X509GetSubjectSummary( + cert, + out subjectSummary); + + using (subjectSummary) + { + if (ret == 1) + { + return CoreFoundation.CFStringToString(subjectSummary); + } + } + + if (ret == 0) + { + return null; + } + + Debug.Fail($"Unexpected return value {ret}"); + throw new CryptographicException(); + } + internal static SafeSecKeyRefHandle X509GetPrivateKeyFromIdentity(SafeSecIdentityHandle identity) { SafeSecKeyRefHandle key; diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c index ff4df6f41fcb2..1833d4a2161ac 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c @@ -106,6 +106,7 @@ static const Entry s_cryptoAppleNative[] = DllImportEntry(AppleCryptoNative_GetOSStatusForChainStatus) DllImportEntry(AppleCryptoNative_X509ChainSetTrustAnchorCertificates) DllImportEntry(AppleCryptoNative_Pbkdf2) + DllImportEntry(AppleCryptoNative_X509GetSubjectSummary) }; EXTERN_C const void* CryptoAppleResolveDllImport(const char* name); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.c index 7d3e61f4b5d57..0b6d1f889bc69 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.c @@ -230,3 +230,15 @@ int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDataRef* ppDa *pOSStatus = *ppDataOut == NULL ? errSecParam : noErr; return (*pOSStatus == noErr); } + +int32_t AppleCryptoNative_X509GetSubjectSummary(SecCertificateRef cert, CFStringRef* ppSummaryOut) +{ + if (ppSummaryOut != NULL) + *ppSummaryOut = NULL; + + if (cert == NULL || ppSummaryOut == NULL) + return kErrorBadInput; + + *ppSummaryOut = SecCertificateCopySubjectSummary(cert); + return (*ppSummaryOut != NULL); +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.h index 28124de10c98d..a0bc58044c3eb 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.h @@ -72,3 +72,13 @@ ppDataOut: Receives a CFDataRef with the exported blob pOSStatus: Receives the result of SecItemExport */ PALEXPORT int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDataRef* ppDataOut, int32_t* pOSStatus); + +/* +Extract a string that contains a human-readable summary of the contents of the certificate + +Returns 1 on success, 0 on failure, any other value indicates invalid state. + +Output: +ppSummaryOut: Receives a CFDataRef with the exported blob +*/ +PALEXPORT int32_t AppleCryptoNative_X509GetSubjectSummary(SecCertificateRef cert, CFStringRef* ppSummaryOut); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs index cb949b8a93f7a..07959c3e77b5a 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs @@ -399,7 +399,26 @@ private void EnsureCertData() return; Debug.Assert(!_certHandle.IsInvalid); - _certData = new CertificateData(Interop.AppleCrypto.X509GetRawData(_certHandle)); + string? subjectSummary = Interop.AppleCrypto.X509GetSubjectSummary(_certHandle); + + try + { + _certData = new CertificateData(Interop.AppleCrypto.X509GetRawData(_certHandle)); + } + catch (CryptographicException e) + { + if (subjectSummary is null) + { + throw; + } + + string message = SR.Format( + SR.Cryptography_X509_CertificateCorrupted, + subjectSummary); + + throw new CryptographicException(message, e); + } + _readCertData = true; } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx index a5c33a43b40b8..322e2bab91d0c 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx @@ -331,6 +331,9 @@ The key contents do not contain a PEM, the content is malformed, or the key does not match the certificate. + + Certificate '{0}' is corrupted. + Enumeration has not started. Call MoveNext.