Skip to content

Commit fb2e61e

Browse files
odhansonbartonjs
andauthored
Add name of corrupted certificate to CryptographicException on Mac
* Add name of corrupted certificate to CryptographicException on Mac When trying to create a CertificateData out of raw X509 byte array it might throw if the data is corrupted. The existing exception message does not provide any information which might help the user identify the corrupted certificate and fix it. This change, makes a native call to SecCertificateCopySubjectSummary which will provide a human readable summary of the certificate, and will generate an exception message using this string. Co-authored-by: Jeremy Barton <[email protected]>
1 parent 44bb2ad commit fb2e61e

File tree

6 files changed

+76
-1
lines changed

6 files changed

+76
-1
lines changed

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.X509.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ private static extern int AppleCryptoNative_X509GetRawData(
2020
out SafeCFDataHandle cfDataOut,
2121
out int pOSStatus);
2222

23+
[DllImport(Libraries.AppleCryptoNative)]
24+
private static extern int AppleCryptoNative_X509GetSubjectSummary(
25+
SafeSecCertificateHandle cert,
26+
out SafeCFStringHandle cfSubjectSummaryOut);
27+
2328
[DllImport(Libraries.AppleCryptoNative)]
2429
private static extern int AppleCryptoNative_X509GetPublicKey(SafeSecCertificateHandle cert, out SafeSecKeyRefHandle publicKey, out int pOSStatus);
2530

@@ -72,6 +77,31 @@ internal static byte[] X509GetRawData(SafeSecCertificateHandle cert)
7277
}
7378
}
7479

80+
internal static string? X509GetSubjectSummary(SafeSecCertificateHandle cert)
81+
{
82+
SafeCFStringHandle subjectSummary;
83+
84+
int ret = AppleCryptoNative_X509GetSubjectSummary(
85+
cert,
86+
out subjectSummary);
87+
88+
using (subjectSummary)
89+
{
90+
if (ret == 1)
91+
{
92+
return CoreFoundation.CFStringToString(subjectSummary);
93+
}
94+
}
95+
96+
if (ret == 0)
97+
{
98+
return null;
99+
}
100+
101+
Debug.Fail($"Unexpected return value {ret}");
102+
throw new CryptographicException();
103+
}
104+
75105
internal static SafeSecKeyRefHandle X509GetPrivateKeyFromIdentity(SafeSecIdentityHandle identity)
76106
{
77107
SafeSecKeyRefHandle key;

src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/entrypoints.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ static const Entry s_cryptoAppleNative[] =
106106
DllImportEntry(AppleCryptoNative_GetOSStatusForChainStatus)
107107
DllImportEntry(AppleCryptoNative_X509ChainSetTrustAnchorCertificates)
108108
DllImportEntry(AppleCryptoNative_Pbkdf2)
109+
DllImportEntry(AppleCryptoNative_X509GetSubjectSummary)
109110
};
110111

111112
EXTERN_C const void* CryptoAppleResolveDllImport(const char* name);

src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,15 @@ int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDataRef* ppDa
230230
*pOSStatus = *ppDataOut == NULL ? errSecParam : noErr;
231231
return (*pOSStatus == noErr);
232232
}
233+
234+
int32_t AppleCryptoNative_X509GetSubjectSummary(SecCertificateRef cert, CFStringRef* ppSummaryOut)
235+
{
236+
if (ppSummaryOut != NULL)
237+
*ppSummaryOut = NULL;
238+
239+
if (cert == NULL || ppSummaryOut == NULL)
240+
return kErrorBadInput;
241+
242+
*ppSummaryOut = SecCertificateCopySubjectSummary(cert);
243+
return (*ppSummaryOut != NULL);
244+
}

src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,13 @@ ppDataOut: Receives a CFDataRef with the exported blob
7272
pOSStatus: Receives the result of SecItemExport
7373
*/
7474
PALEXPORT int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDataRef* ppDataOut, int32_t* pOSStatus);
75+
76+
/*
77+
Extract a string that contains a human-readable summary of the contents of the certificate
78+
79+
Returns 1 on success, 0 on failure, any other value indicates invalid state.
80+
81+
Output:
82+
ppSummaryOut: Receives a CFDataRef with the exported blob
83+
*/
84+
PALEXPORT int32_t AppleCryptoNative_X509GetSubjectSummary(SecCertificateRef cert, CFStringRef* ppSummaryOut);

src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,26 @@ private void EnsureCertData()
399399
return;
400400

401401
Debug.Assert(!_certHandle.IsInvalid);
402-
_certData = new CertificateData(Interop.AppleCrypto.X509GetRawData(_certHandle));
402+
string? subjectSummary = Interop.AppleCrypto.X509GetSubjectSummary(_certHandle);
403+
404+
try
405+
{
406+
_certData = new CertificateData(Interop.AppleCrypto.X509GetRawData(_certHandle));
407+
}
408+
catch (CryptographicException e)
409+
{
410+
if (subjectSummary is null)
411+
{
412+
throw;
413+
}
414+
415+
string message = SR.Format(
416+
SR.Cryptography_X509_CertificateCorrupted,
417+
subjectSummary);
418+
419+
throw new CryptographicException(message, e);
420+
}
421+
403422
_readCertData = true;
404423
}
405424
}

src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,9 @@
331331
<data name="Cryptography_X509_NoOrMismatchedPemKey" xml:space="preserve">
332332
<value>The key contents do not contain a PEM, the content is malformed, or the key does not match the certificate.</value>
333333
</data>
334+
<data name="Cryptography_X509_CertificateCorrupted" xml:space="preserve">
335+
<value>Certificate '{0}' is corrupted.</value>
336+
</data>
334337
<data name="InvalidOperation_EnumNotStarted" xml:space="preserve">
335338
<value>Enumeration has not started. Call MoveNext.</value>
336339
</data>

0 commit comments

Comments
 (0)