internal override int SetClientCertificate(SafeHandle ld, X509Certificate2 certificate) { const int verifyDepth = 6; var certData = MarshalUtils.ByteArrayToGnuTlsDatum(certificate.Export(X509ContentType.Cert)); var certs = MarshalUtils.AllocHGlobalIntPtrArray(verifyDepth); var privateKey = (RSA)certificate.PrivateKey; var keyData = MarshalUtils.ByteArrayToGnuTlsDatum(privateKey.ToRsaPrivateKey()); try { var max = verifyDepth; var tlsCtx = IntPtr.Zero; var isServer = 0; ThrowIfError(ld, ldap_set_option(new LdapHandle(IntPtr.Zero), (int)Native.LdapOption.LDAP_OPT_X_TLS_NEWCTX, ref isServer), nameof(ldap_set_option)); ThrowIfError(ld, ldap_get_option(new LdapHandle(IntPtr.Zero), (int)Native.LdapOption.LDAP_OPT_X_TLS_CTX, ref tlsCtx), nameof(ldap_set_option)); var key = IntPtr.Zero; var cred = Marshal.ReadIntPtr(tlsCtx); ThrowIfGnuTlsError(NativeMethodsLinux.gnutls_x509_privkey_init(ref key), nameof(NativeMethodsLinux.gnutls_x509_privkey_init)); ThrowIfGnuTlsError( NativeMethodsLinux.gnutls_x509_privkey_import(key, keyData, NativeMethodsLinux.GNUTLS_X509_FMT.GNUTLS_X509_FMT_DER), nameof(NativeMethodsLinux.gnutls_x509_privkey_import)); ThrowIfGnuTlsError( NativeMethodsLinux.gnutls_x509_crt_list_import(certs, ref max, certData, NativeMethodsLinux.GNUTLS_X509_FMT.GNUTLS_X509_FMT_DER, 0), nameof(NativeMethodsLinux.gnutls_x509_crt_list_import)); var cert = Marshal.ReadIntPtr(certs); // If there's only one cert and it's not self-signed, then we have to build the cert chain. if (max == 1 && !IsSelfSigned(cert)) { for (var i = 1; i < verifyDepth; i++) { cert = Marshal.ReadIntPtr(certs, (i - 1) * IntPtr.Size); var issuer = Marshal.ReadIntPtr(certs, i * IntPtr.Size); if (NativeMethodsLinux.gnutls_certificate_get_issuer(cred, cert, ref issuer, 0) != 0) { break; } Marshal.WriteIntPtr(certs, i * IntPtr.Size, issuer); max++; if (IsSelfSigned(issuer)) { break; } } } ThrowIfGnuTlsError(NativeMethodsLinux.gnutls_certificate_set_x509_key(cred, certs, max, key), nameof(NativeMethodsLinux.gnutls_certificate_set_x509_key)); NativeMethodsLinux.gnutls_certificate_set_verify_flags(cred, 0); return(ldap_set_option(new LdapHandle(IntPtr.Zero), (int)Native.LdapOption.LDAP_OPT_X_TLS_CTX, tlsCtx)); } finally { MarshalUtils.TlsDatumFree(certData); MarshalUtils.TlsDatumFree(keyData); if (certs != IntPtr.Zero) { Marshal.FreeHGlobal(certs); } } }