Proper fix for compilation issue caused by deprecated API in Mojave (dotnet/corefx...
authorMaryam Ariyan <maryam.ariyan@microsoft.com>
Tue, 10 Jul 2018 16:09:46 +0000 (12:09 -0400)
committerGitHub <noreply@github.com>
Tue, 10 Jul 2018 16:09:46 +0000 (12:09 -0400)
* Proper fix for compilation issue caused by deprecated API in macOS Mojave by
using dlsym to call available API rather than suppressing deprecation warnings.

Fixes: dotnet/corefx#30599

Commit migrated from https://github.com/dotnet/corefx/commit/92b4826a7648b05678e9340e98af3453a9d064a2

src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/CMakeLists.txt
src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.c
src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509.h
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/X509Pal.cs

index 8feda36..fcb96e1 100644 (file)
@@ -25,9 +25,6 @@ set(NATIVECRYPTO_SOURCES
     pal_x509chain.c
 )
 
-# Temporary workaround for dotnet/corefx issue #30599
-add_compile_options(-Wno-deprecated-declarations)
-
 add_library(System.Security.Cryptography.Native.Apple
     SHARED
     ${NATIVECRYPTO_SOURCES}
index f5d51ea..d15ed63 100644 (file)
@@ -3,9 +3,14 @@
 // See the LICENSE file in the project root for more information.
 
 #include "pal_x509.h"
+#include <dlfcn.h>
+#include <pthread.h>
 
 static const int32_t kErrOutItemsNull = -3;
 static const int32_t kErrOutItemsEmpty = -2;
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+static SecKeyRef (*secCertificateCopyKey)(SecCertificateRef);
+static OSStatus (*secCertificateCopyPublicKey)(SecCertificateRef, SecKeyRef*);
 
 typedef const struct OpaqueSecCertificateRef * ConstSecCertificateRef;
 typedef const struct OpaqueSecIdentityRef * ConstSecIdentityRef;
@@ -41,6 +46,12 @@ AppleCryptoNative_X509DemuxAndRetainHandle(CFTypeRef handle, SecCertificateRef*
     return 1;
 }
 
+static void InitCertificateCopy()
+{
+    secCertificateCopyKey = (SecKeyRef (*)(SecCertificateRef))dlsym(RTLD_DEFAULT, "SecCertificateCopyKey");
+    secCertificateCopyPublicKey = (OSStatus (*)(SecCertificateRef, SecKeyRef*))dlsym(RTLD_DEFAULT, "SecCertificateCopyPublicKey");
+}
+
 int32_t
 AppleCryptoNative_X509GetPublicKey(SecCertificateRef cert, SecKeyRef* pPublicKeyOut, int32_t* pOSStatusOut)
 {
@@ -50,9 +61,23 @@ AppleCryptoNative_X509GetPublicKey(SecCertificateRef cert, SecKeyRef* pPublicKey
         *pOSStatusOut = noErr;
 
     if (cert == NULL || pPublicKeyOut == NULL || pOSStatusOut == NULL)
-        return kErrorBadInput;
+        return kErrorUnknownState;
 
-    *pOSStatusOut = SecCertificateCopyPublicKey(cert, pPublicKeyOut);
+    pthread_once (&once, InitCertificateCopy);
+    // SecCertificateCopyPublicKey was deprecated in 10.14, so use SecCertificateCopyKey on the systems that have it (10.14+),
+    // and SecCertificateCopyPublicKey on the systems that don’t.
+    if (secCertificateCopyKey != NULL)
+    {
+        *pPublicKeyOut = (*secCertificateCopyKey)(cert);
+    }
+    else if (secCertificateCopyPublicKey != NULL)
+    {
+        *pOSStatusOut = (*secCertificateCopyPublicKey)(cert, pPublicKeyOut);
+    }
+    else
+    {
+        return kErrorBadInput;
+    }
     return (*pOSStatusOut == noErr);
 }
 
index 544a940..1f468bd 100644 (file)
@@ -42,7 +42,7 @@ Returns 1 on success, 0 on failure, any other value on invalid state.
 
 Output:
 pPublicKeyOut: Receives a CFRetain()ed SecKeyRef for the public key
-pOSStatusOut: Receives the result of SecCertificateCopyPublicKey
+pOSStatusOut: Receives the result of SecCertificateCopyKey or SecCertificateCopyPublicKey, depending on the OS version.
 */
 DLLEXPORT int32_t
 AppleCryptoNative_X509GetPublicKey(SecCertificateRef cert, SecKeyRef* pPublicKeyOut, int32_t* pOSStatusOut);
index 1056f0c..a2fee97 100644 (file)
@@ -33,6 +33,11 @@ namespace Internal.Cryptography.Pal
                         case Oids.RsaRsa:
                             return new RSAImplementation.RSASecurityTransforms(key);
                         case Oids.DsaDsa:
+                            if (key.IsInvalid) 
+                            {
+                                // SecCertificateCopyKey returns null for DSA, so fall back to manually building it.
+                                return DecodeDsaPublicKey(encodedKeyValue, encodedParameters);
+                            } 
                             return new DSAImplementation.DSASecurityTransforms(key);
                         case Oids.Ecc:
                             return new ECDsaImplementation.ECDsaSecurityTransforms(key);