Exemplo n.º 1
0
            public void MoveTo(X509Certificate2Collection collection)
            {
                foreach (UnixPkcs12Reader.CertAndKey certAndKey in _pkcs12.EnumerateAll())
                {
                    AppleCertificatePal pal = (AppleCertificatePal)certAndKey.Cert !;
                    SafeSecKeyRefHandle?safeSecKeyRefHandle =
                        ApplePkcs12Reader.GetPrivateKey(certAndKey.Key);

                    using (safeSecKeyRefHandle)
                    {
                        ICertificatePal newPal;

                        // SecItemImport doesn't seem to respect non-exportable import for PKCS#8,
                        // only PKCS#12.
                        //
                        // So, as part of reading this PKCS#12 we now need to write the minimum
                        // PKCS#12 in a normalized form, and ask the OS to import it.
                        if (!_exportable && safeSecKeyRefHandle != null)
                        {
                            newPal = AppleCertificatePal.ImportPkcs12NonExportable(
                                pal,
                                safeSecKeyRefHandle,
                                _password,
                                _keychain);
                        }
                        else
                        {
                            newPal = pal.MoveToKeychain(_keychain, safeSecKeyRefHandle) ?? pal;
                        }

                        X509Certificate2 cert = new X509Certificate2(newPal);
                        collection.Add(cert);
                    }
                }
            }
Exemplo n.º 2
0
 public void Dispose()
 {
     PrivateKey?.Dispose();
     PrivateKey = null;
     PublicKey?.Dispose();
     PublicKey = null !;
 }
 internal static byte[] SecKeyExport(
     SafeSecKeyRefHandle?key,
     bool exportPrivate,
     string password)
 {
     using (SafeCFDataHandle cfData = SecKeyExportData(key, exportPrivate, password))
     {
         return(CoreFoundation.CFGetData(cfData));
     }
 }
Exemplo n.º 4
0
        internal AppleCertificatePal?MoveToKeychain(SafeKeychainHandle keychain, SafeSecKeyRefHandle?privateKey)
        {
            SafeSecIdentityHandle?identity = Interop.AppleCrypto.X509MoveToKeychain(
                _certHandle,
                keychain,
                privateKey);

            if (identity != null)
            {
                return(new AppleCertificatePal(identity));
            }

            return(null);
        }
        internal static SafeSecIdentityHandle?X509MoveToKeychain(
            SafeSecCertificateHandle cert,
            SafeKeychainHandle targetKeychain,
            SafeSecKeyRefHandle?privateKey)
        {
            SafeSecIdentityHandle identityHandle;
            int osStatus;

            int result = AppleCryptoNative_X509MoveToKeychain(
                cert,
                targetKeychain,
                privateKey ?? SafeSecKeyRefHandle.InvalidHandle,
                out identityHandle,
                out osStatus);

            if (result == 0)
            {
                identityHandle.Dispose();
                throw CreateExceptionForOSStatus(osStatus);
            }

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

            if (privateKey?.IsInvalid == false)
            {
                // If a PFX has a mismatched association between a private key and the
                // certificate public key then MoveToKeychain will write the NULL SecIdentityRef
                // (after cleaning up the temporary key).
                //
                // When that happens, just treat the import as public-only.
                if (!identityHandle.IsInvalid)
                {
                    return(identityHandle);
                }
            }

            // If the cert in the PFX had no key, but it was imported with PersistKeySet (imports into
            // the default keychain) and a matching private key was already there, then an
            // identityHandle could be found. But that's not desirable, since neither Windows or Linux would
            // do that matching.
            //
            // So dispose the handle, no matter what.
            identityHandle.Dispose();
            return(null);
        }
Exemplo n.º 6
0
        private static AppleCertificatePal ImportPkcs12(
            ReadOnlySpan <byte> rawData,
            SafePasswordHandle password,
            bool exportable,
            SafeKeychainHandle keychain)
        {
            using (ApplePkcs12Reader reader = new ApplePkcs12Reader(rawData))
            {
                reader.Decrypt(password, ephemeralSpecified: false);

                UnixPkcs12Reader.CertAndKey certAndKey = reader.GetSingleCert();
                AppleCertificatePal         pal        = (AppleCertificatePal)certAndKey.Cert !;

                SafeSecKeyRefHandle?safeSecKeyRefHandle =
                    ApplePkcs12Reader.GetPrivateKey(certAndKey.Key);

                AppleCertificatePal?newPal;

                using (safeSecKeyRefHandle)
                {
                    // SecItemImport doesn't seem to respect non-exportable import for PKCS#8,
                    // only PKCS#12.
                    //
                    // So, as part of reading this PKCS#12 we now need to write the minimum
                    // PKCS#12 in a normalized form, and ask the OS to import it.
                    if (!exportable && safeSecKeyRefHandle != null)
                    {
                        using (pal)
                        {
                            return(ImportPkcs12NonExportable(pal, safeSecKeyRefHandle, password, keychain));
                        }
                    }

                    newPal = pal.MoveToKeychain(keychain, safeSecKeyRefHandle);

                    if (newPal != null)
                    {
                        pal.Dispose();
                    }
                }

                // If no new PAL came back, it means we moved the cert, but had no private key.
                return(newPal ?? pal);
            }
        }
        internal static SafeCFDataHandle SecKeyExportData(
            SafeSecKeyRefHandle?key,
            bool exportPrivate,
            ReadOnlySpan <char> password)
        {
            SafeCreateHandle exportPassword = exportPrivate
                ? CoreFoundation.CFStringCreateFromSpan(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();
                }
            }

            if (ret == 1)
            {
                return(cfData);
            }

            cfData.Dispose();

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

            Debug.Fail($"AppleCryptoNative_SecKeyExport returned {ret}");
            throw new CryptographicException();
        }
            private byte[]? DeriveSecretAgreement(ECDiffieHellmanPublicKey otherPartyPublicKey, IncrementalHash?hasher)
            {
                if (!(otherPartyPublicKey is ECDiffieHellmanSecurityTransformsPublicKey secTransPubKey))
                {
                    secTransPubKey =
                        new ECDiffieHellmanSecurityTransformsPublicKey(otherPartyPublicKey.ExportParameters());
                }

                try
                {
                    SafeSecKeyRefHandle otherPublic = secTransPubKey.KeyHandle;

                    if (Interop.AppleCrypto.EccGetKeySizeInBits(otherPublic) != KeySize)
                    {
                        throw new ArgumentException(
                                  SR.Cryptography_ArgECDHKeySizeMismatch,
                                  nameof(otherPartyPublicKey));
                    }

                    SafeSecKeyRefHandle?thisPrivate = GetKeys().PrivateKey;

                    if (thisPrivate == null)
                    {
                        throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
                    }

                    // Since Apple only supports secp256r1, secp384r1, and secp521r1; and 521 fits in
                    // 66 bytes ((521 + 7) / 8), the Span path will always succeed.
                    Span <byte> secretSpan = stackalloc byte[66];

                    byte[]? secret = Interop.AppleCrypto.EcdhKeyAgree(
                        thisPrivate,
                        otherPublic,
                        secretSpan,
                        out int bytesWritten);

                    // Either we wrote to the span or we returned an array, but not both, and not neither.
                    // ("neither" would have thrown)
                    Debug.Assert(
                        (bytesWritten == 0) != (secret == null),
                        $"bytesWritten={bytesWritten}, (secret==null)={secret == null}");

                    if (hasher == null)
                    {
                        return(secret ?? secretSpan.Slice(0, bytesWritten).ToArray());
                    }

                    if (secret == null)
                    {
                        hasher.AppendData(secretSpan.Slice(0, bytesWritten));
                    }
                    else
                    {
                        hasher.AppendData(secret);
                        Array.Clear(secret, 0, secret.Length);
                    }

                    return(null);
                }
                finally
                {
                    if (!ReferenceEquals(otherPartyPublicKey, secTransPubKey))
                    {
                        secTransPubKey.Dispose();
                    }
                }
            }
 private static partial int AppleCryptoNative_SecKeyExport(
     SafeSecKeyRefHandle?key,
     int exportPrivate,
     SafeCreateHandle cfExportPassphrase,
     out SafeCFDataHandle cfDataOut,
     out int pOSStatus);
Exemplo n.º 10
0
 private SecKeyPair(SafeSecKeyRefHandle publicKey, SafeSecKeyRefHandle?privateKey)
 {
     PublicKey  = publicKey;
     PrivateKey = privateKey;
 }
Exemplo n.º 11
0
        private ICertificatePal CopyWithPrivateKey(SafeSecKeyRefHandle?privateKey)
        {
            if (privateKey == null)
            {
                // Both Windows and Linux/OpenSSL are unaware if they bound a public or private key.
                // Here, we do know.  So throw if we can't do what they asked.
                throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
            }

            SafeKeychainHandle keychain = Interop.AppleCrypto.SecKeychainItemCopyKeychain(privateKey);

            // If we're using a key already in a keychain don't add the certificate to that keychain here,
            // do it in the temporary add/remove in the shim.
            SafeKeychainHandle cloneKeychain = SafeTemporaryKeychainHandle.InvalidHandle;

            if (keychain.IsInvalid)
            {
                keychain      = Interop.AppleCrypto.CreateTemporaryKeychain();
                cloneKeychain = keychain;
            }

            // Because SecIdentityRef only has private constructors we need to have the cert and the key
            // in the same keychain.  That almost certainly means we're going to need to add this cert to a
            // keychain, and when a cert that isn't part of a keychain gets added to a keychain then the
            // interior pointer of "what keychain did I come from?" used by SecKeychainItemCopyKeychain gets
            // set. That makes this function have side effects, which is not desired.
            //
            // It also makes reference tracking on temporary keychains broken, since the cert can
            // DangerousRelease a handle it didn't DangerousAddRef on.  And so CopyWithPrivateKey makes
            // a temporary keychain, then deletes it before anyone has a chance to (e.g.) export the
            // new identity as a PKCS#12 blob.
            //
            // Solution: Clone the cert, like we do in Windows.
            SafeSecCertificateHandle tempHandle;

            {
                byte[]                export     = RawData;
                const bool            exportable = false;
                SafeSecIdentityHandle identityHandle;
                tempHandle = Interop.AppleCrypto.X509ImportCertificate(
                    export,
                    X509ContentType.Cert,
                    SafePasswordHandle.InvalidHandle,
                    cloneKeychain,
                    exportable,
                    out identityHandle);

                Debug.Assert(identityHandle.IsInvalid, "identityHandle should be IsInvalid");
                identityHandle.Dispose();

                Debug.Assert(!tempHandle.IsInvalid, "tempHandle should not be IsInvalid");
            }

            using (keychain)
                using (tempHandle)
                {
                    SafeSecIdentityHandle identityHandle = Interop.AppleCrypto.X509CopyWithPrivateKey(
                        tempHandle,
                        privateKey,
                        keychain);

                    AppleCertificatePal newPal = new AppleCertificatePal(identityHandle);
                    return(newPal);
                }
        }