예제 #1
0
        private void UpdateFromMem(IntPtr statusPtr)
        {
            var result = new _gpgme_import_status();

            Marshal.PtrToStructure(statusPtr, result);

            if (result.fpr != IntPtr.Zero)
            {
                Fpr = Gpgme.PtrToStringAnsi(result.fpr);
            }
            _status = result.status;
            Result  = result.result;
            if (result.next != IntPtr.Zero)
            {
                Next = new ImportStatus(result.next);
            }
        }
예제 #2
0
            public void Add(string name, string value, SignatureNotationFlags flags)
            {
                _ctx.EnsureValid();

                IntPtr name_ptr  = IntPtr.Zero;
                IntPtr value_ptr = IntPtr.Zero;

                if (name != null)
                {
                    name_ptr = Gpgme.StringToCoTaskMemUTF8(name);
                }
                if (value != null)
                {
                    value_ptr = Gpgme.StringToCoTaskMemUTF8(value);
                }

                int err = libgpgme.NativeMethods.gpgme_sig_notation_add(
                    _ctx.CtxPtr,
                    name_ptr,
                    value_ptr,
                    (gpgme_sig_notation_flags_t)flags);

                if (name_ptr != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(name_ptr);
                }
                if (value_ptr != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(value_ptr);
                }

                gpg_err_code_t errcode = libgpgerror.gpg_err_code(err);

                if (errcode == gpg_err_code_t.GPG_ERR_NO_ERROR)
                {
                    return;
                }
                if (errcode == gpg_err_code_t.GPG_ERR_INV_VALUE)
                {
                    throw new ArgumentException("NAME and VALUE are in an invalid combination.");
                }

                throw new GeneralErrorException("An unexpected error occurred. Error: "
                                                + errcode.ToString());
            }
예제 #3
0
        private void UpdateFromMem(IntPtr sigPtr)
        {
            var newsig = new _gpgme_new_signature();

            Marshal.PtrToStructure(sigPtr, newsig);

            Type            = (SignatureMode)newsig.type;
            PubkeyAlgorithm = (KeyAlgorithm)newsig.pubkey_algo;
            HashAlgorithm   = (HashAlgorithm)newsig.hash_algo;
            Fingerprint     = Gpgme.PtrToStringUTF8(newsig.fpr);
            SignatureClass  = newsig.sig_class;
            _timestamp      = (long)newsig.timestamp;

            if (!newsig.next.Equals(IntPtr.Zero))
            {
                Next = new NewSignature(newsig.next);
            }
        }
        private void UpdateFromMem(IntPtr sigPtr)
        {
            _gpgme_new_signature newsig = new _gpgme_new_signature();

            Marshal.PtrToStructure(sigPtr, newsig);

            type        = (SignatureMode)newsig.type;
            pubkey_algo = (KeyAlgorithm)newsig.pubkey_algo;
            hash_algo   = (HashAlgorithm)newsig.hash_algo;
            fpr         = Gpgme.PtrToStringUTF8(newsig.fpr);
            sig_class   = (long)newsig.sig_class;
            timestamp   = (long)newsig.timestamp;

            if (!newsig.next.Equals(IntPtr.Zero))
            {
                next = new NewSignature(newsig.next);
            }
        }
예제 #5
0
        /// <summary>
        /// Converts a GPGME error code into an exception
        /// </summary>
        /// <param name="code">GPGME error code</param>
        /// <returns>Exception</returns>
        public static Exception CreateException(gpg_err_code_t code)
        {
            string message;

            Gpgme.GetStrError((int)code, out message);
            message = $"#{code}: ${message ?? "No error message available"}";

            switch (code)
            {
            case gpg_err_code_t.GPG_ERR_AMBIGUOUS_NAME:
                return(new AmbiguousKeyException(message));

            case gpg_err_code_t.GPG_ERR_BAD_PASSPHRASE:
                return(new BadPassphraseException(message));

            case gpg_err_code_t.GPG_ERR_CONFLICT:
                return(new KeyConflictException(message));

            case gpg_err_code_t.GPG_ERR_DECRYPT_FAILED:
                return(new DecryptionFailedException(message));

            case gpg_err_code_t.GPG_ERR_INV_VALUE:
                return(new InvalidPtrException(message));

            case gpg_err_code_t.GPG_ERR_EBADF:
                return(new InvalidDataBufferException(message));

            case gpg_err_code_t.GPG_ERR_ENOMEM:
                return(new OutOfMemoryException(message));

            case gpg_err_code_t.GPG_ERR_NO_DATA:
                return(new NoDataException(message));

            case gpg_err_code_t.GPG_ERR_NO_PUBKEY:
                return(new KeyNotFoundException(message));

            case gpg_err_code_t.GPG_ERR_UNUSABLE_SECKEY:
                return(new InvalidKeyException(message));

            default:
                return(new GeneralErrorException(message));
            }
        }
예제 #6
0
        private void UpdateFromMem(IntPtr uidPtr)
        {
            var userid = (_gpgme_user_id)
                         Marshal.PtrToStructure(uidPtr, typeof(_gpgme_user_id));

            Revoked  = userid.revoked;
            Invalid  = userid.invalid;
            Validity = (Validity)userid.validity;
            Uid      = Gpgme.PtrToStringUTF8(userid.uid);
            Name     = Gpgme.PtrToStringUTF8(userid.name);
            Comment  = Gpgme.PtrToStringUTF8(userid.comment);
            Email    = Gpgme.PtrToStringUTF8(userid.email);

            Signatures = userid.signatures != IntPtr.Zero
                ? new KeySignature(userid.signatures)
                : null;

            Next = userid.next != IntPtr.Zero
                ? new UserId(userid.next)
                : null;
        }
예제 #7
0
        private int PassphraseCb(IntPtr hook, IntPtr uid_hint, IntPtr passphrase_info,
                                 int prev_was_bad, int fd)
        {
            char[] passwd = null;

            string hint = Gpgme.PtrToStringUTF8(uid_hint);
            string info = Gpgme.PtrToStringUTF8(passphrase_info);

            bool prevbad = prev_was_bad > 0;

            PassphraseResult result;

            try {
                var pinfo = new PassphraseInfo(hook, hint, info, prevbad);
                result = _passphrase_delegate(this, pinfo, ref passwd);
            } catch (Exception ex) {
                _last_callback_exception = ex;
                passwd = "".ToCharArray();
                result = PassphraseResult.Canceled;
            }

            if (fd > 0)
            {
                byte[] utf8_passwd = Gpgme.ConvertCharArrayToUTF8(passwd, 0);

                libgpgme.gpgme_io_write(fd, utf8_passwd, (UIntPtr)utf8_passwd.Length);
                libgpgme.gpgme_io_write(fd, new[] { (byte)0 }, (UIntPtr)1);

                // try to wipe the passwords
                int i;
                for (i = 0; i < utf8_passwd.Length; i++)
                {
                    utf8_passwd[i] = 0;
                }
            }

            return((int)result);
        }
예제 #8
0
        internal void UpdateFromMem(IntPtr keyPtr)
        {
            _gpgme_key key = (_gpgme_key)
                             Marshal.PtrToStructure(keyPtr,
                                                    typeof(_gpgme_key));

            this.keyPtr = keyPtr;

            revoked          = key.revoked;
            expired          = key.expired;
            disabled         = key.disabled;
            invalid          = key.invalid;
            can_encrypt      = key.can_encrypt;
            can_sign         = key.can_sign;
            can_certify      = key.can_certify;
            can_authenticate = key.can_authenticate;
            is_qualified     = key.is_qualified;
            secret           = key.secret;

            protocol    = (Protocol)key.protocol;
            owner_trust = (Validity)key.owner_trust;
            keylistmode = (KeylistMode)key.keylist_mode;

            issuer_name   = Gpgme.PtrToStringUTF8(key.issuer_name);
            issuer_serial = Gpgme.PtrToStringAnsi(key.issuer_serial);
            chain_id      = Gpgme.PtrToStringAnsi(key.chain_id);

            if (key.subkeys != (IntPtr)0)
            {
                subkeys = new Subkey(key.subkeys);
            }

            if (key.uids != (IntPtr)0)
            {
                uids = new UserId(key.uids);
            }
        }
예제 #9
0
        // internal callback function
        private int _edit_cb(
            IntPtr opaque,
            int status,
            IntPtr args,
            int fd)
        {
            gpgme_status_code_t statuscode = (gpgme_status_code_t)status;
            string cmdargs = Gpgme.PtrToStringUTF8(args);
            Stream fdstream;

            if (fd > 0)
            {
                fdstream = Gpgme.ConvertToStream(fd, FileAccess.Write);
            }
            else
            {
                fdstream = null;
            }

            int result = 0;

            try
            {
                // call user callback function.
                result = KeyEditCallback(
                    opaque,
                    (KeyEditStatusCode)statuscode,
                    cmdargs,
                    fdstream);
            }
            catch (Exception ex)
            {
                LastCallbackException = ex;
            }

            return(result);
        }
예제 #10
0
        // internal callback function
        private int KeyEditCallback(
            IntPtr opaque,
            int status,
            IntPtr args,
            int fd)
        {
            var    statuscode = (gpgme_status_code_t)status;
            string cmdargs    = Gpgme.PtrToStringUTF8(args);

            int result = 0;

            try {
                // call user callback function.
                result = KeyEditCallback(
                    opaque,
                    (KeyEditStatusCode)statuscode,
                    cmdargs,
                    fd);
            } catch (Exception ex) {
                LastCallbackException = ex;
            }

            return(result);
        }
        public Key[] GetKeyList(string[] pattern, bool secretOnly)
        {
            if (ctx == null ||
                !(ctx.IsValid))
            {
                throw new InvalidContextException();
            }

            List <Key> list = new List <Key>();

            int reserved    = 0;
            int secret_only = 0;

            if (secretOnly)
            {
                secret_only = 1;
            }

            IntPtr[] parray = null;
            if (pattern != null)
            {
                parray = Gpgme.StringToCoTaskMemUTF8(pattern);
            }

            lock (ctx.CtxLock)
            {
                // no deadlock because the query is made by the same thread
                Protocol proto = ctx.Protocol;

                int err = 0;

                if (parray != null)
                {
                    err = libgpgme.gpgme_op_keylist_ext_start(
                        ctx.CtxPtr,
                        parray,
                        secret_only,
                        reserved);
                }
                else
                {
                    err = libgpgme.gpgme_op_keylist_start(
                        ctx.CtxPtr,
                        IntPtr.Zero,
                        secret_only);
                }

                while (err == 0)
                {
                    IntPtr keyPtr = (IntPtr)0;
                    err = libgpgme.gpgme_op_keylist_next(ctx.CtxPtr, out keyPtr);
                    if (err != 0)
                    {
                        break;
                    }

                    Key key = null;

                    if (proto == Protocol.OpenPGP)
                    {
                        key = new PgpKey(keyPtr);
                    }
                    else if (proto == Protocol.CMS)
                    {
                        key = new X509Key(keyPtr);
                    }
                    else
                    {
                        key = new Key(keyPtr);
                    }

                    list.Add(key);

                    //libgpgme.gpgme_key_release(keyPtr);
                }

                // Free memory
                if (parray != null)
                {
                    Gpgme.FreeStringArray(parray);
                }

                gpg_err_code_t errcode = libgpgme.gpgme_err_code(err);
                if (errcode != gpg_err_code_t.GPG_ERR_EOF)
                {
                    libgpgme.gpgme_op_keylist_end(ctx.CtxPtr);
                    throw new GpgmeException(Gpgme.GetStrError(err), err);
                }
            }
            return(list.ToArray());
        }
        private void UpdateFromMem(IntPtr sigPtr)
        {
            /* Work around memory layout problem (bug?) on Windows systems
             * with libgpgme <= 1.1.8
             * //_gpgme_signature sig = new _gpgme_signature();
             *
             */
            if (!libgpgme.IsWindows ||
                (Gpgme.Version.Major >= 1 &&
                 Gpgme.Version.Minor >= 2)
                )
            {
                _gpgme_signature unixsig = new _gpgme_signature();
                Marshal.PtrToStructure(sigPtr, unixsig);

                summary         = (SignatureSummary)unixsig.summary;
                fpr             = Gpgme.PtrToStringUTF8(unixsig.fpr);
                status          = unixsig.status;
                timestamp       = unixsig.timestamp;
                exp_timestamp   = unixsig.exp_timestamp;
                validity        = (Validity)unixsig.validity;
                validity_reason = unixsig.validity_reason;
                pubkey_algo     = (KeyAlgorithm)unixsig.pubkey_algo;
                hash_algo       = (HashAlgorithm)unixsig.hash_algo;
                pka_address     = Gpgme.PtrToStringUTF8(unixsig.pka_address);
                wrong_key_usage = unixsig.wrong_key_usage;
                pka_trust       = (PkaStatus)unixsig.pka_trust;
                chain_model     = unixsig.chain_model;

                if (unixsig.notations != IntPtr.Zero)
                {
                    notations = new SignatureNotation(unixsig.notations);
                }

                if (unixsig.next != IntPtr.Zero)
                {
                    next = new Signature(unixsig.next);
                }
            }
            else
            {
                _gpgme_signature_windows winsig = new _gpgme_signature_windows();
                Marshal.PtrToStructure(sigPtr, winsig);

                summary         = (SignatureSummary)winsig.summary;
                fpr             = Gpgme.PtrToStringUTF8(winsig.fpr);
                status          = winsig.status;
                timestamp       = winsig.timestamp;
                exp_timestamp   = winsig.exp_timestamp;
                validity        = (Validity)winsig.validity;
                validity_reason = winsig.validity_reason;
                pubkey_algo     = (KeyAlgorithm)winsig.pubkey_algo;
                hash_algo       = (HashAlgorithm)winsig.hash_algo;
                pka_address     = Gpgme.PtrToStringUTF8(winsig.pka_address);
                wrong_key_usage = winsig.wrong_key_usage;
                pka_trust       = (PkaStatus)winsig.pka_trust;
                chain_model     = winsig.chain_model;

                if (winsig.notations != IntPtr.Zero)
                {
                    notations = new SignatureNotation(winsig.notations);
                }

                if (winsig.next != IntPtr.Zero)
                {
                    next = new Signature(winsig.next);
                }
            }
        }
예제 #13
0
        public EncryptionResult Encrypt(Key[] recipients, EncryptFlags flags, GpgmeData plain, GpgmeData cipher)
        {
            if (plain == null)
            {
                throw new ArgumentNullException("plain", "Source data buffer must be supplied.");
            }
            if (!(plain.IsValid))
            {
                throw new InvalidDataBufferException("The specified source data buffer is invalid.");
            }
            if (cipher == null)
            {
                throw new ArgumentNullException("cipher", "Destination data buffer must be supplied.");
            }
            if (!(cipher.IsValid))
            {
                throw new InvalidDataBufferException("The specified destination data buffer is invalid.");
            }
            if (!IsValid)
            {
                throw new InvalidContextException();
            }

            IntPtr[] recp = Gpgme.KeyArrayToIntPtrArray(recipients);

            lock (CtxLock) {
#if (VERBOSE_DEBUG)
                DebugOutput("gpgme_op_encrypt(..) START");
#endif
                int err = libgpgme.gpgme_op_encrypt(
                    CtxPtr,
                    recp,
                    (gpgme_encrypt_flags_t)flags,
                    plain.dataPtr,
                    cipher.dataPtr);

#if (VERBOSE_DEBUG)
                DebugOutput("gpgme_op_encrypt(..) DONE");
#endif

                gpg_err_code_t errcode = libgpgerror.gpg_err_code(err);
                switch (errcode)
                {
                case gpg_err_code_t.GPG_ERR_NO_ERROR:
                    break;

                case gpg_err_code_t.GPG_ERR_UNUSABLE_PUBKEY:
                    break;

                case gpg_err_code_t.GPG_ERR_GENERAL:     // Bug? should be GPG_ERR_UNUSABLE_PUBKEY
                    break;

                case gpg_err_code_t.GPG_ERR_INV_VALUE:
                    throw new InvalidPtrException(
                              "Either the context, recipient key array, plain text or cipher text pointer is invalid.");

                case gpg_err_code_t.GPG_ERR_BAD_PASSPHRASE:
                    throw new BadPassphraseException();

                case gpg_err_code_t.GPG_ERR_EBADF:
                    throw new InvalidDataBufferException(
                              "The source (plain) or destination (cipher) data buffer is invalid for encryption.");

                default:
                    throw new GeneralErrorException("An unexpected error "
                                                    + errcode.ToString()
                                                    + " (" + err.ToString(CultureInfo.InvariantCulture)
                                                    + ") occurred.");
                }
                IntPtr rst_ptr = libgpgme.gpgme_op_encrypt_result(CtxPtr);
#if (VERBOSE_DEBUG)
                DebugOutput("gpgme_op_encrypt_result(..) DONE");
#endif
                GC.KeepAlive(recp);
                GC.KeepAlive(recipients);
                GC.KeepAlive(plain);
                GC.KeepAlive(cipher);

                if (rst_ptr != IntPtr.Zero)
                {
                    var enc_rst = new EncryptionResult(rst_ptr);
                    return(enc_rst);
                }
                throw new GeneralErrorException("An unexpected error occurred. " + errcode.ToString());
            }
        }
예제 #14
0
        private void UpdateFromMem(IntPtr sigPtr)
        {
            /* Work around memory layout problem (bug?) on Windows systems
             * with libgpgme <= 1.1.8
             * //_gpgme_signature sig = new _gpgme_signature();
             *
             */
            if (!libgpgme.IsWindows ||
                (Gpgme.Version.Major >= 1 &&
                 Gpgme.Version.Minor >= 2)
                )
            {
                var unixsig = new _gpgme_signature();
                Marshal.PtrToStructure(sigPtr, unixsig);

                Summary          = (SignatureSummary)unixsig.summary;
                Fingerprint      = Gpgme.PtrToStringUTF8(unixsig.fpr);
                _status          = unixsig.status;
                _timestamp       = unixsig.timestamp;
                _exp_timestamp   = unixsig.exp_timestamp;
                Validity         = (Validity)unixsig.validity;
                _validity_reason = unixsig.validity_reason;
                PubkeyAlgorithm  = (KeyAlgorithm)unixsig.pubkey_algo;
                HashAlgorithm    = (HashAlgorithm)unixsig.hash_algo;
                PKAAddress       = Gpgme.PtrToStringUTF8(unixsig.pka_address);
                WrongKeyUsage    = unixsig.wrong_key_usage;
                PKATrust         = unixsig.pka_trust;
                ChainModel       = unixsig.chain_model;

                if (unixsig.notations != IntPtr.Zero)
                {
                    Notations = new SignatureNotation(unixsig.notations);
                }

                if (unixsig.next != IntPtr.Zero)
                {
                    Next = new Signature(unixsig.next);
                }
            }
            else
            {
                var winsig = new _gpgme_signature_windows();
                Marshal.PtrToStructure(sigPtr, winsig);

                Summary          = (SignatureSummary)winsig.summary;
                Fingerprint      = Gpgme.PtrToStringUTF8(winsig.fpr);
                _status          = winsig.status;
                _timestamp       = winsig.timestamp;
                _exp_timestamp   = winsig.exp_timestamp;
                Validity         = (Validity)winsig.validity;
                _validity_reason = winsig.validity_reason;
                PubkeyAlgorithm  = (KeyAlgorithm)winsig.pubkey_algo;
                HashAlgorithm    = (HashAlgorithm)winsig.hash_algo;
                PKAAddress       = Gpgme.PtrToStringUTF8(winsig.pka_address);
                WrongKeyUsage    = winsig.wrong_key_usage;
                PKATrust         = winsig.pka_trust;
                ChainModel       = winsig.chain_model;

                if (winsig.notations != IntPtr.Zero)
                {
                    Notations = new SignatureNotation(winsig.notations);
                }

                if (winsig.next != IntPtr.Zero)
                {
                    Next = new Signature(winsig.next);
                }
            }
        }
예제 #15
0
        public TrustItem[] GetTrustList(string pattern, int maxlevel)
        {
            if (Context == null ||
                !(Context.IsValid))
            {
                throw new InvalidContextException();
            }

            if (pattern == null || pattern.Equals(String.Empty))
            {
                throw new ArgumentException("An invalid pattern has been specified.");
            }

            IntPtr pattern_ptr = Gpgme.StringToCoTaskMemUTF8(pattern);

            var lst = new List <TrustItem>();

            lock (Context.CtxLock) {
                int            err     = libgpgme.NativeMethods.gpgme_op_trustlist_start(Context.CtxPtr, pattern_ptr, maxlevel);
                gpg_err_code_t errcode = libgpgerror.gpg_err_code(err);

                if (errcode != gpg_err_code_t.GPG_ERR_NO_ERROR)
                {
                    if (pattern_ptr != IntPtr.Zero)
                    {
                        Marshal.FreeCoTaskMem(pattern_ptr);
                    }
                    throw GpgmeError.CreateException(errcode);
                }

                while (errcode == gpg_err_code_t.GPG_ERR_NO_ERROR)
                {
                    IntPtr item_ptr;
                    err     = libgpgme.NativeMethods.gpgme_op_trustlist_next(Context.CtxPtr, out item_ptr);
                    errcode = libgpgerror.gpg_err_code(err);

                    if (errcode == gpg_err_code_t.GPG_ERR_NO_ERROR)
                    {
                        lst.Add(new TrustItem(item_ptr));
                    }
                }
                // Release context if there are any pending trustlist items
                libgpgme.NativeMethods.gpgme_op_trustlist_end(Context.CtxPtr);

                if (pattern_ptr != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pattern_ptr);
                }

                if (errcode != gpg_err_code_t.GPG_ERR_EOF)
                {
                    throw GpgmeError.CreateException(errcode);
                }
            }

            if (lst.Count == 0)
            {
                return(new TrustItem[0]);
            }
            return(lst.ToArray());
        }
        public GenkeyResult GenerateKey(Protocol protocoltype, KeyParameters keyparms)
        {
            if (!ctx.IsValid)
            {
                throw new InvalidContextException();
            }

            if (keyparms == null)
            {
                throw new ArgumentNullException("No KeyParameters object supplied. Bad programmer! *spank* *spank*");
            }

            if (keyparms.Email == null ||
                keyparms.Email.Equals(String.Empty))
            {
                throw new ArgumentException("No email address has been supplied.");
            }

            // Convert the key parameter to an XML string for GPGME
            string parms = keyparms.GetXmlText(protocoltype);

            // Convert key parameter XML string to UTF8 and retrieve the memory pointer
            IntPtr parmsPtr = Gpgme.StringToCoTaskMemUTF8(parms);

            GenkeyResult   keyresult = null;
            int            err       = 0;
            gpg_err_code_t errcode   = gpg_err_code_t.GPG_ERR_NO_ERROR;

            lock (ctx.CtxLock)
            {
                // Protocol specific key generation
                switch (protocoltype)
                {
                case Protocol.OpenPGP:
                    err     = libgpgme.gpgme_op_genkey(ctx.CtxPtr, parmsPtr, (IntPtr)0, (IntPtr)0);
                    errcode = libgpgme.gpgme_err_code(err);
                    if (errcode == gpg_err_code_t.GPG_ERR_NO_ERROR)
                    {
                        IntPtr resultPtr = libgpgme.gpgme_op_genkey_result(ctx.CtxPtr);
                        if (!resultPtr.Equals((IntPtr)0))
                        {
                            keyresult = new GenkeyResult(resultPtr);
                        }
                        else
                        {
                            errcode = gpg_err_code_t.GPG_ERR_GENERAL;
                        }
                    }
                    break;

                default:
                    // free memory
                    if (parmsPtr != IntPtr.Zero)
                    {
                        Marshal.FreeCoTaskMem(parmsPtr);
                        parmsPtr = IntPtr.Zero;
                    }
                    throw new NotSupportedException("The protocol " + protocoltype + " is currently not supported for key generation.");
                }
            }

            // free memory
            if (parmsPtr != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(parmsPtr);
                parmsPtr = IntPtr.Zero;
            }

            if (errcode == gpg_err_code_t.GPG_ERR_INV_VALUE)
            {
                throw new ArgumentException("The key parameters are invalid.");
            }
            if (errcode == gpg_err_code_t.GPG_ERR_NOT_SUPPORTED)
            {
                throw new NotSupportedException("The PUBLIC or SECRET part is invalid. Error: " + err.ToString());
            }
            if (errcode != gpg_err_code_t.GPG_ERR_NO_ERROR)
            {
                throw new GeneralErrorException("No key has been created by the backend.");
            }

            return(keyresult);
        }
        public TrustItem[] GetTrustList(string pattern, int maxlevel)
        {
            if (ctx == null ||
                !(ctx.IsValid))
            {
                throw new InvalidContextException();
            }

            if (pattern == null || pattern.Equals(String.Empty))
            {
                throw new ArgumentException("An invalid pattern has been specified.");
            }

            IntPtr patternPtr = Gpgme.StringToCoTaskMemUTF8(pattern);

            List <TrustItem> lst = new List <TrustItem>();

            lock (ctx.CtxLock)
            {
                int            err     = libgpgme.gpgme_op_trustlist_start(ctx.CtxPtr, patternPtr, maxlevel);
                gpg_err_code_t errcode = libgpgerror.gpg_err_code(err);

                if (errcode != gpg_err_code_t.GPG_ERR_NO_ERROR)
                {
                    if (patternPtr != IntPtr.Zero)
                    {
                        Marshal.FreeCoTaskMem(patternPtr);
                        patternPtr = IntPtr.Zero;
                    }
                    throw new GeneralErrorException("An unexpected error occurred. Error: " + err.ToString());
                }

                while (errcode == gpg_err_code_t.GPG_ERR_NO_ERROR)
                {
                    IntPtr itemPtr = IntPtr.Zero;
                    err     = libgpgme.gpgme_op_trustlist_next(ctx.CtxPtr, out itemPtr);
                    errcode = libgpgerror.gpg_err_code(err);

                    if (errcode == gpg_err_code_t.GPG_ERR_NO_ERROR)
                    {
                        lst.Add(new TrustItem(itemPtr));
                    }
                }
                // Release context if there are any pending trustlist items
                err = libgpgme.gpgme_op_trustlist_end(ctx.CtxPtr);

                if (patternPtr != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(patternPtr);
                    patternPtr = IntPtr.Zero;
                }

                if (errcode != gpg_err_code_t.GPG_ERR_EOF)
                {
                    throw new GeneralErrorException("An unexpected error occurred. " + errcode.ToString());
                }
            }

            if (lst.Count == 0)
            {
                return(new TrustItem[0]);
            }
            else
            {
                return(lst.ToArray());
            }
        }
        public EncryptionResult EncryptAndSign(Key[] recipients, EncryptFlags flags, GpgmeData plain, GpgmeData cipher)
        {
            if (IsValid)
            {
                if (plain == null)
                {
                    throw new ArgumentNullException("Source data buffer must be supplied.");
                }
                if (!(plain.IsValid))
                {
                    throw new InvalidDataBufferException("The specified source data buffer is invalid.");
                }

                if (cipher == null)
                {
                    throw new ArgumentNullException("Destination data buffer must be supplied.");
                }
                if (!(cipher.IsValid))
                {
                    throw new InvalidDataBufferException("The specified destination data buffer is invalid.");
                }

                IntPtr[] recp = Gpgme.KeyArrayToIntPtrArray(recipients);

                lock (CtxLock)
                {
                    int err = libgpgme.gpgme_op_encrypt_sign(
                        CtxPtr,
                        recp,
                        (gpgme_encrypt_flags_t)flags,
                        plain.dataPtr,
                        cipher.dataPtr);

                    gpg_err_code_t errcode = libgpgerror.gpg_err_code(err);
                    switch (errcode)
                    {
                    case gpg_err_code_t.GPG_ERR_NO_ERROR:
                        break;

                    case gpg_err_code_t.GPG_ERR_UNUSABLE_PUBKEY:
                        break;

                    case gpg_err_code_t.GPG_ERR_GENERAL:        // Bug? should be GPG_ERR_UNUSABLE_PUBKEY
                        break;

                    case gpg_err_code_t.GPG_ERR_UNUSABLE_SECKEY:
                        throw new InvalidKeyException("There is one or more invalid signing key(s) in the current context.");

                    case gpg_err_code_t.GPG_ERR_INV_VALUE:
                        throw new InvalidPtrException("Either the context, recipient key array, plain text or cipher text pointer is invalid.");

                    case gpg_err_code_t.GPG_ERR_BAD_PASSPHRASE:
                        throw new BadPassphraseException();

                    default:
                        throw new GeneralErrorException("An unexpected error "
                                                        + errcode.ToString()
                                                        + " (" + err.ToString()
                                                        + ") occurred.");
                    }
                    IntPtr rstPtr = libgpgme.gpgme_op_encrypt_result(CtxPtr);

                    GC.KeepAlive(recp);
                    GC.KeepAlive(recipients);
                    GC.KeepAlive(plain);
                    GC.KeepAlive(cipher);

                    if (rstPtr != IntPtr.Zero)
                    {
                        EncryptionResult encRst = new EncryptionResult(rstPtr);
                        return(encRst);
                    }
                    else
                    {
                        throw new GeneralErrorException("An unexpected error occurred. " + errcode.ToString());
                    }
                }
            }
            else
            {
                throw new InvalidContextException();
            }
        }