Exemplo n.º 1
0
        public static bool SslCheckHostnameMatch(SafeSslHandle handle, string hostName, DateTime notBefore)
        {
            int result;
            // The IdnMapping converts Unicode input into the IDNA punycode sequence.
            // It also does host case normalization.  The bypass logic would be something
            // like "all characters being within [a-z0-9.-]+"
            //
            // The SSL Policy (SecPolicyCreateSSL) has been verified as not inherently supporting
            // IDNA as of macOS 10.12.1 (Sierra).  If it supports low-level IDNA at a later date,
            // this code could be removed.
            //
            // It was verified as supporting case invariant match as of 10.12.1 (Sierra).
            string matchName = s_idnMapping.GetAscii(hostName);

            using (SafeCFDateHandle cfNotBefore = CoreFoundation.CFDateCreate(notBefore))
                using (SafeCreateHandle cfHostname = CoreFoundation.CFStringCreateWithCString(matchName))
                {
                    result = AppleCryptoNative_SslIsHostnameMatch(handle, cfHostname, cfNotBefore);
                }

            switch (result)
            {
            case 0:
                return(false);

            case 1:
                return(true);

            default:
                Debug.Fail($"AppleCryptoNative_SslIsHostnameMatch returned {result}");
                throw new SslException();
            }
        }
        internal static byte[] X509ExportPfx(IntPtr[] certHandles, SafePasswordHandle exportPassword)
        {
            SafeCreateHandle cfPassphrase    = s_emptyExportString;
            bool             releasePassword = false;

            try
            {
                if (!exportPassword.IsInvalid)
                {
                    exportPassword.DangerousAddRef(ref releasePassword);
                    IntPtr passwordHandle = exportPassword.DangerousGetHandle();

                    if (passwordHandle != IntPtr.Zero)
                    {
                        cfPassphrase = CoreFoundation.CFStringCreateWithCString(passwordHandle);
                    }
                }

                return(X509Export(X509ContentType.Pkcs12, cfPassphrase, certHandles));
            }
            finally
            {
                if (releasePassword)
                {
                    exportPassword.DangerousRelease();
                }

                if (cfPassphrase != s_emptyExportString)
                {
                    cfPassphrase.Dispose();
                }
            }
        }
Exemplo n.º 3
0
        internal static unsafe void SslCtxSetAlpnProtos(SafeSslHandle ctx, List <SslApplicationProtocol> protocols)
        {
            SafeCreateHandle cfProtocolsRefs = null;

            SafeCreateHandle[] cfProtocolsArrayRef = null;
            try
            {
                if (protocols.Count == 1 && protocols[0] == SslApplicationProtocol.Http2)
                {
                    cfProtocolsRefs = s_cfAlpnHttp211Protocols;
                }
                else if (protocols.Count == 1 && protocols[0] == SslApplicationProtocol.Http11)
                {
                    cfProtocolsRefs = s_cfAlpnHttp11Protocols;
                }
                else if (protocols.Count == 2 && protocols[0] == SslApplicationProtocol.Http2 && protocols[1] == SslApplicationProtocol.Http11)
                {
                    cfProtocolsRefs = s_cfAlpnHttp211Protocols;
                }
                else
                {
                    // we did not match common case. This is more expensive path allocating Core Foundation objects.
                    cfProtocolsArrayRef = new SafeCreateHandle[protocols.Count];
                    IntPtr[] protocolsPtr = new System.IntPtr[protocols.Count];

                    for (int i = 0; i < protocols.Count; i++)
                    {
                        cfProtocolsArrayRef[i] = CoreFoundation.CFStringCreateWithCString(protocols[i].ToString());
                        protocolsPtr[i]        = cfProtocolsArrayRef[i].DangerousGetHandle();
                    }

                    cfProtocolsRefs = CoreFoundation.CFArrayCreate(protocolsPtr, (UIntPtr)protocols.Count);
                }

                int osStatus;
                int result = SSLSetALPNProtocols(ctx, cfProtocolsRefs, out osStatus);
                if (result != 1)
                {
                    throw CreateExceptionForOSStatus(osStatus);
                }
            }
            finally
            {
                if (cfProtocolsArrayRef != null)
                {
                    for (int i = 0; i < cfProtocolsArrayRef.Length; i++)
                    {
                        cfProtocolsArrayRef[i]?.Dispose();
                    }

                    cfProtocolsRefs?.Dispose();
                }
            }
        }
Exemplo n.º 4
0
        internal static SafeCFArrayHandle X509ImportCollection(
            ReadOnlySpan <byte> bytes,
            X509ContentType contentType,
            SafePasswordHandle importPassword)
        {
            SafeCreateHandle  cfPassphrase    = s_emptyExportString;
            bool              releasePassword = false;
            SafeCFArrayHandle collectionHandle;
            int osStatus;

            try
            {
                if (!importPassword.IsInvalid)
                {
                    importPassword.DangerousAddRef(ref releasePassword);
                    IntPtr passwordHandle = importPassword.DangerousGetHandle();

                    if (passwordHandle != IntPtr.Zero)
                    {
                        cfPassphrase = CoreFoundation.CFStringCreateWithCString(passwordHandle);
                    }
                }

                osStatus = AppleCryptoNative_X509ImportCollection(
                    ref MemoryMarshal.GetReference(bytes),
                    bytes.Length,
                    contentType,
                    cfPassphrase,
                    out collectionHandle);

                if (osStatus == 0)
                {
                    return(collectionHandle);
                }
            }
            finally
            {
                if (releasePassword)
                {
                    importPassword.DangerousRelease();
                }

                if (cfPassphrase != s_emptyExportString)
                {
                    cfPassphrase.Dispose();
                }
            }

            collectionHandle.Dispose();
            throw CreateExceptionForOSStatus(osStatus);
        }
        internal static byte[] SecKeyExport(
            SafeSecKeyRefHandle key,
            bool exportPrivate,
            string password)
        {
            SafeCreateHandle exportPassword = exportPrivate
                ? CoreFoundation.CFStringCreateWithCString(password)
                : s_nullExportString;

            int ret;
            SafeCFDataHandle cfData;
            int osStatus;

            try
            {
                ret = AppleCryptoNative_SecKeyExport(
                    key,
                    exportPrivate ? 1 : 0,
                    exportPassword,
                    out cfData,
                    out osStatus);
            }
            finally
            {
                if (exportPassword != s_nullExportString)
                {
                    exportPassword.Dispose();
                }
            }

            byte[] exportedData;

            using (cfData)
            {
                if (ret == 0)
                {
                    throw CreateExceptionForOSStatus(osStatus);
                }

                if (ret != 1)
                {
                    Debug.Fail($"AppleCryptoNative_SecKeyExport returned {ret}");
                    throw new CryptographicException();
                }

                exportedData = CoreFoundation.CFGetData(cfData);
            }

            return(exportedData);
        }
Exemplo n.º 6
0
 public TypedPtr <CFString> CFStringCreateWithCString(IntPtr allocator, byte[] buffer)
 {
     return(CoreFoundation.CFStringCreateWithCString(allocator, buffer, CFStringBuiltInEncodings.kCFStringEncodingUTF8));
 }
        internal static SafeCFArrayHandle X509ImportCollection(
            byte[] bytes,
            X509ContentType contentType,
            SafePasswordHandle importPassword,
            SafeKeychainHandle keychain,
            bool exportable)
        {
            SafeCreateHandle cfPassphrase    = s_nullExportString;
            bool             releasePassword = false;

            int ret;
            SafeCFArrayHandle collectionHandle;
            int osStatus;

            try
            {
                if (!importPassword.IsInvalid)
                {
                    importPassword.DangerousAddRef(ref releasePassword);
                    IntPtr passwordHandle = importPassword.DangerousGetHandle();

                    if (passwordHandle != IntPtr.Zero)
                    {
                        cfPassphrase = CoreFoundation.CFStringCreateWithCString(passwordHandle);
                    }
                }

                ret = AppleCryptoNative_X509ImportCollection(
                    bytes,
                    bytes.Length,
                    contentType,
                    cfPassphrase,
                    keychain,
                    exportable ? 1 : 0,
                    out collectionHandle,
                    out osStatus);

                if (ret == 1)
                {
                    return(collectionHandle);
                }
            }
            finally
            {
                if (releasePassword)
                {
                    importPassword.DangerousRelease();
                }

                if (cfPassphrase != s_nullExportString)
                {
                    cfPassphrase.Dispose();
                }
            }

            collectionHandle.Dispose();

            const int SeeOSStatus         = 0;
            const int ImportReturnedEmpty = -2;
            const int ImportReturnedNull  = -3;

            switch (ret)
            {
            case SeeOSStatus:
                throw CreateExceptionForOSStatus(osStatus);

            case ImportReturnedNull:
            case ImportReturnedEmpty:
                throw new CryptographicException();

            default:
                Debug.Fail($"Unexpected return value {ret}");
                throw new CryptographicException();
            }
        }
Exemplo n.º 8
0
        internal static DerSequenceReader SecKeyExport(
            SafeSecKeyRefHandle key,
            bool exportPrivate)
        {
            // Apple requires all private keys to be exported encrypted, but since we're trying to export
            // as parsed structures we will need to decrypt it for the user.
            const string ExportPassword = "******";

            SafeCreateHandle exportPassword = exportPrivate
                ? CoreFoundation.CFStringCreateWithCString(ExportPassword)
                : s_nullExportString;

            int ret;
            SafeCFDataHandle cfData;
            int osStatus;

            try
            {
                ret = AppleCryptoNative_SecKeyExport(
                    key,
                    exportPrivate ? 1 : 0,
                    exportPassword,
                    out cfData,
                    out osStatus);
            }
            finally
            {
                if (exportPassword != s_nullExportString)
                {
                    exportPassword.Dispose();
                }
            }

            byte[] exportedData;

            using (cfData)
            {
                if (ret == 0)
                {
                    throw CreateExceptionForOSStatus(osStatus);
                }

                if (ret != 1)
                {
                    Debug.Fail($"AppleCryptoNative_SecKeyExport returned {ret}");
                    throw new CryptographicException();
                }

                exportedData = CoreFoundation.CFGetData(cfData);
            }

            DerSequenceReader reader = new DerSequenceReader(exportedData);

            if (!exportPrivate)
            {
                return(reader);
            }

            byte tag = reader.PeekTag();

            // PKCS#8 defines two structures, PrivateKeyInfo, which starts with an integer,
            // and EncryptedPrivateKey, which starts with an encryption algorithm (DER sequence).
            if (tag == (byte)DerSequenceReader.DerTag.Integer)
            {
                return(reader);
            }

            const byte ConstructedSequence =
                DerSequenceReader.ConstructedFlag | (byte)DerSequenceReader.DerTag.Sequence;

            if (tag == ConstructedSequence)
            {
                return(ReadEncryptedPkcs8Blob(ExportPassword, reader));
            }

            Debug.Fail($"Data was neither PrivateKey or EncryptedPrivateKey: {tag:X2}");
            throw new CryptographicException();
        }