예제 #1
0
        /// <summary>
        /// Queries a string-valued context attribute by the named attribute.
        /// </summary>
        /// <param name="attrib">The string-valued attribute to query.</param>
        /// <returns></returns>
        private string QueryContextString(CContextQueryAttrib attrib)
        {
            CSecPkgContext_String stringAttrib;
            CSecurityStatus       status = CSecurityStatus.InternalError;
            string result = null;
            bool   gotRef = false;

            if (attrib != CContextQueryAttrib.Names && attrib != CContextQueryAttrib.Authority)
            {
                throw new InvalidOperationException("QueryContextString can only be used to query context Name and Authority attributes");
            }

            stringAttrib = new CSecPkgContext_String();

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                this.ContextHandle.DangerousAddRef(ref gotRef);
            }
            catch (Exception)
            {
                if (gotRef)
                {
                    this.ContextHandle.DangerousRelease();
                    gotRef = false;
                }
                throw;
            }
            finally
            {
                if (gotRef)
                {
                    status = CContextNativeMethods.QueryContextAttributes_String(
                        ref this.ContextHandle.rawHandle,
                        attrib,
                        ref stringAttrib
                        );

                    this.ContextHandle.DangerousRelease();

                    if (status == CSecurityStatus.OK)
                    {
                        result = Marshal.PtrToStringUni(stringAttrib.StringResult);
                        CContextNativeMethods.FreeContextBuffer(stringAttrib.StringResult);
                    }
                }
            }

            if (status == CSecurityStatus.Unsupported)
            {
                return(null);
            }
            else if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to query the context's associated user name", status);
            }

            return(result);
        }
        /// <summary>
        /// Returns a list of all known security package providers and their properties.
        /// </summary>
        /// <returns></returns>
        public static CSecPkgInfo[] EnumeratePackages()
        {
            CSecurityStatus status = CSecurityStatus.InternalError;

            CSecPkgInfo[] packages = null;
            IntPtr        pkgArrayPtr;
            IntPtr        pkgPtr;
            int           numPackages = 0;
            int           pkgSize     = Marshal.SizeOf(typeof(CSecPkgInfo));

            pkgArrayPtr = new IntPtr();

            RuntimeHelpers.PrepareConstrainedRegions();
            try { }
            finally
            {
                status = CNativeMethods.EnumerateSecurityPackages(ref numPackages, ref pkgArrayPtr);

                if (pkgArrayPtr != IntPtr.Zero)
                {
                    try
                    {
                        if (status == CSecurityStatus.OK)
                        {
                            // Bwooop Bwooop Alocation Alert
                            // 1) We allocate the array
                            // 2) We allocate the individual elements in the array (they're class objects).
                            // 3) We allocate the strings in the individual elements in the array when we
                            //    call Marshal.PtrToStructure()

                            packages = new CSecPkgInfo[numPackages];

                            for (int i = 0; i < numPackages; i++)
                            {
                                packages[i] = new CSecPkgInfo();
                            }

                            for (int i = 0; i < numPackages; i++)
                            {
                                pkgPtr = IntPtr.Add(pkgArrayPtr, i * pkgSize);

                                Marshal.PtrToStructure(pkgPtr, packages[i]);
                            }
                        }
                    }
                    finally
                    {
                        CNativeMethods.FreeContextBuffer(pkgArrayPtr);
                    }
                }
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to enumerate security package providers", status);
            }

            return(packages);
        }
예제 #3
0
        /// <summary>
        /// Signs the message using the context's session key.
        /// </summary>
        /// <remarks>
        /// The structure of the returned buffer is as follows:
        ///  - 4 bytes, unsigned big-endian integer indicating the length of the plaintext message
        ///  - 2 bytes, unsigned big-endian integer indicating the length of the signture
        ///  - The plaintext message
        ///  - The message's signature.
        /// </remarks>
        /// <param name="message"></param>
        /// <returns></returns>
        public byte[] MakeSignature(byte[] message)
        {
            CSecurityStatus status = CSecurityStatus.InternalError;

            CSecPkgContext_Sizes sizes;
            CSecureBuffer        dataBuffer;
            CSecureBuffer        signatureBuffer;
            CSecureBufferAdapter adapter;

            CheckLifecycle();

            sizes = QueryBufferSizes();

            dataBuffer      = new CSecureBuffer(new byte[message.Length], CBufferType.Data);
            signatureBuffer = new CSecureBuffer(new byte[sizes.MaxSignature], CBufferType.Token);

            Array.Copy(message, dataBuffer.Buffer, message.Length);

            using (adapter = new CSecureBufferAdapter(new[] { dataBuffer, signatureBuffer }))
            {
                status = CContextNativeMethods.SafeMakeSignature(
                    this.ContextHandle,
                    0,
                    adapter,
                    0
                    );
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to create message signature.", status);
            }

            byte[] outMessage;
            int    position = 0;

            // Enough room for
            //  - original message length (4 bytes)
            //  - signature length        (2 bytes)
            //  - original message
            //  - signature

            outMessage = new byte[4 + 2 + dataBuffer.Length + signatureBuffer.Length];

            CByteWriter.WriteInt32_BE(dataBuffer.Length, outMessage, position);
            position += 4;

            CByteWriter.WriteInt16_BE((Int16)signatureBuffer.Length, outMessage, position);
            position += 2;

            Array.Copy(dataBuffer.Buffer, 0, outMessage, position, dataBuffer.Length);
            position += dataBuffer.Length;

            Array.Copy(signatureBuffer.Buffer, 0, outMessage, position, signatureBuffer.Length);
            position += signatureBuffer.Length;

            return(outMessage);
        }
예제 #4
0
        protected override bool ReleaseHandle()
        {
            CSecurityStatus status = CContextNativeMethods.DeleteSecurityContext(
                ref base.rawHandle
                );

            base.ReleaseHandle();

            return(status == CSecurityStatus.OK);
        }
        protected override bool ReleaseHandle()
        {
            CSecurityStatus status = CCredentialNativeMethods.FreeCredentialsHandle(
                ref base.rawHandle
                );

            base.ReleaseHandle();

            return(status == CSecurityStatus.OK);
        }
예제 #6
0
        /// <summary>
        /// Queries the security package's expections regarding message/token/signature/padding buffer sizes.
        /// </summary>
        /// <returns></returns>
        private CSecPkgContext_Sizes QueryBufferSizes()
        {
            CSecPkgContext_Sizes sizes  = new CSecPkgContext_Sizes();
            CSecurityStatus      status = CSecurityStatus.InternalError;
            bool gotRef = false;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                this.ContextHandle.DangerousAddRef(ref gotRef);
            }
            catch (Exception)
            {
                if (gotRef)
                {
                    this.ContextHandle.DangerousRelease();
                    gotRef = false;
                }

                throw;
            }
            finally
            {
                if (gotRef)
                {
                    status = CContextNativeMethods.QueryContextAttributes_Sizes(
                        ref this.ContextHandle.rawHandle,
                        CContextQueryAttrib.Sizes,
                        ref sizes
                        );
                    this.ContextHandle.DangerousRelease();
                }
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to query context buffer size attributes", status);
            }

            return(sizes);
        }
        /// <summary>
        /// Returns the properties of the named package.
        /// </summary>
        /// <param name="packageName">The name of the package.</param>
        /// <returns></returns>
        public static CSecPkgInfo GetPackageCapabilities(string packageName)
        {
            CSecPkgInfo     info;
            CSecurityStatus status = CSecurityStatus.InternalError;

            IntPtr rawInfoPtr;

            rawInfoPtr = new IntPtr();
            info       = new CSecPkgInfo();

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            { }
            finally
            {
                status = CNativeMethods.QuerySecurityPackageInfo(packageName, ref rawInfoPtr);

                if (rawInfoPtr != IntPtr.Zero)
                {
                    try
                    {
                        if (status == CSecurityStatus.OK)
                        {
                            // This performs allocations as it makes room for the strings contained in the SecPkgInfo class.
                            Marshal.PtrToStructure(rawInfoPtr, info);
                        }
                    }
                    finally
                    {
                        CNativeMethods.FreeContextBuffer(rawInfoPtr);
                    }
                }
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to query security package provider details", status);
            }

            return(info);
        }
예제 #8
0
        /// <summary>
        /// Safely invokes the native VerifySignature function, making sure that handle ref counting is
        /// performed in a proper CER.
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="qualityOfProtection"></param>
        /// <param name="adapter"></param>
        /// <param name="sequenceNumber"></param>
        /// <returns></returns>
        internal static CSecurityStatus SafeVerifySignature(
            CSafeContextHandle handle,
            int qualityOfProtection,
            CSecureBufferAdapter adapter,
            int sequenceNumber)
        {
            bool            gotRef = false;
            CSecurityStatus status = CSecurityStatus.InternalError;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                handle.DangerousAddRef(ref gotRef);
            }
            catch (Exception)
            {
                if (gotRef)
                {
                    handle.DangerousRelease();
                    gotRef = false;
                }

                throw;
            }
            finally
            {
                if (gotRef)
                {
                    status = CContextNativeMethods.VerifySignature(
                        ref handle.rawHandle,
                        adapter.Handle,
                        sequenceNumber,
                        qualityOfProtection
                        );

                    handle.DangerousRelease();
                }
            }

            return(status);
        }
        private void Init(CCredentialUse use)
        {
            string          packageName;
            CTimeStamp      rawExpiry = new CTimeStamp();
            CSecurityStatus status    = CSecurityStatus.InternalError;

            // -- Package --
            // Copy off for the call, since this.SecurityPackage is a property.
            packageName = this.SecurityPackage;

            this.Handle = new CSafeCredentialHandle();

            // The finally clause is the actual constrained region. The VM pre-allocates any stack space,
            // performs any allocations it needs to prepare methods for execution, and postpones any
            // instances of the 'uncatchable' exceptions (ThreadAbort, StackOverflow, OutOfMemory).
            RuntimeHelpers.PrepareConstrainedRegions();
            try { }
            finally
            {
                status = CCredentialNativeMethods.AcquireCredentialsHandle(
                    null,
                    packageName,
                    use,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    ref this.Handle.rawHandle,
                    ref rawExpiry
                    );
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to call AcquireCredentialHandle", status);
            }

            this.Expiry = rawExpiry.ToDateTime();
        }
예제 #10
0
        /// <summary>
        /// Verifies the signature of a signed message
        /// </summary>
        /// <remarks>
        /// The expected structure of the signed message buffer is as follows:
        ///  - 4 bytes, unsigned integer in big endian format indicating the length of the plaintext message
        ///  - 2 bytes, unsigned integer in big endian format indicating the length of the signture
        ///  - The plaintext message
        ///  - The message's signature.
        /// </remarks>
        /// <param name="signedMessage">The packed signed message.</param>
        /// <param name="origMessage">The extracted original message.</param>
        /// <returns>True if the message has a valid signature, false otherwise.</returns>
        public bool VerifySignature(byte[] signedMessage, out byte[] origMessage)
        {
            CSecurityStatus status = CSecurityStatus.InternalError;

            CSecPkgContext_Sizes sizes;
            CSecureBuffer        dataBuffer;
            CSecureBuffer        signatureBuffer;
            CSecureBufferAdapter adapter;

            CheckLifecycle();

            sizes = QueryBufferSizes();

            if (signedMessage.Length < 2 + 4 + sizes.MaxSignature)
            {
                throw new ArgumentException("Input message is too small to possibly fit a valid message");
            }

            int position = 0;
            int messageLen;
            int sigLen;

            messageLen = CByteWriter.ReadInt32_BE(signedMessage, 0);
            position  += 4;

            sigLen    = CByteWriter.ReadInt16_BE(signedMessage, position);
            position += 2;

            if (messageLen + sigLen + 2 + 4 > signedMessage.Length)
            {
                throw new ArgumentException("The buffer contains invalid data - the embedded length data does not add up.");
            }

            dataBuffer = new CSecureBuffer(new byte[messageLen], CBufferType.Data);
            Array.Copy(signedMessage, position, dataBuffer.Buffer, 0, messageLen);
            position += messageLen;

            signatureBuffer = new CSecureBuffer(new byte[sigLen], CBufferType.Token);
            Array.Copy(signedMessage, position, signatureBuffer.Buffer, 0, sigLen);
            position += sigLen;

            using (adapter = new CSecureBufferAdapter(new[] { dataBuffer, signatureBuffer }))
            {
                status = CContextNativeMethods.SafeVerifySignature(
                    this.ContextHandle,
                    0,
                    adapter,
                    0
                    );
            }

            if (status == CSecurityStatus.OK)
            {
                origMessage = dataBuffer.Buffer;
                return(true);
            }
            else if (status == CSecurityStatus.MessageAltered ||
                     status == CSecurityStatus.OutOfSequence)
            {
                origMessage = null;
                return(false);
            }
            else
            {
                throw new CSSPIException("Failed to determine the veracity of a signed message.", status);
            }
        }
예제 #11
0
        /// <summary>
        /// Encrypts the byte array using the context's session key.
        /// </summary>
        /// <remarks>
        /// The structure of the returned data is as follows:
        ///  - 2 bytes, an unsigned big-endian integer indicating the length of the trailer buffer size
        ///  - 4 bytes, an unsigned big-endian integer indicating the length of the message buffer size.
        ///  - 2 bytes, an unsigned big-endian integer indicating the length of the encryption padding buffer size.
        ///  - The trailer buffer
        ///  - The message buffer
        ///  - The padding buffer.
        /// </remarks>
        /// <param name="input">The raw message to encrypt.</param>
        /// <returns>The packed and encrypted message.</returns>
        public byte[] Encrypt(byte[] input)
        {
            // The message is encrypted in place in the buffer we provide to Win32 EncryptMessage
            CSecPkgContext_Sizes sizes;

            CSecureBuffer        trailerBuffer;
            CSecureBuffer        dataBuffer;
            CSecureBuffer        paddingBuffer;
            CSecureBufferAdapter adapter;

            CSecurityStatus status = CSecurityStatus.InvalidHandle;

            byte[] result;

            CheckLifecycle();

            sizes = QueryBufferSizes();

            trailerBuffer = new CSecureBuffer(new byte[sizes.SecurityTrailer], CBufferType.Token);
            dataBuffer    = new CSecureBuffer(new byte[input.Length], CBufferType.Data);
            paddingBuffer = new CSecureBuffer(new byte[sizes.BlockSize], CBufferType.Padding);

            Array.Copy(input, dataBuffer.Buffer, input.Length);

            using (adapter = new CSecureBufferAdapter(new[] { trailerBuffer, dataBuffer, paddingBuffer }))
            {
                status = CContextNativeMethods.SafeEncryptMessage(
                    this.ContextHandle,
                    0,
                    adapter,
                    0
                    );
            }

            if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to encrypt message", status);
            }

            int position = 0;

            // Enough room to fit:
            //  -- 2 bytes for the trailer buffer size
            //  -- 4 bytes for the message size
            //  -- 2 bytes for the padding size.
            //  -- The encrypted message
            result = new byte[2 + 4 + 2 + trailerBuffer.Length + dataBuffer.Length + paddingBuffer.Length];

            CByteWriter.WriteInt16_BE((short)trailerBuffer.Length, result, position);
            position += 2;

            CByteWriter.WriteInt32_BE(dataBuffer.Length, result, position);
            position += 4;

            CByteWriter.WriteInt16_BE((short)paddingBuffer.Length, result, position);
            position += 2;

            Array.Copy(trailerBuffer.Buffer, 0, result, position, trailerBuffer.Length);
            position += trailerBuffer.Length;

            Array.Copy(dataBuffer.Buffer, 0, result, position, dataBuffer.Length);
            position += dataBuffer.Length;

            Array.Copy(paddingBuffer.Buffer, 0, result, position, paddingBuffer.Length);
            position += paddingBuffer.Length;

            return(result);
        }
 /// <summary>
 /// Initializes a new instance of the SSPIException class from serialization data.
 /// </summary>
 /// <param name="info"></param>
 /// <param name="context"></param>
 protected CSSPIException(SerializationInfo info, StreamingContext context)
     : base(info, context)
 {
     this.message   = info.GetString("messsage");
     this.errorCode = (CSecurityStatus)info.GetUInt32("errorCode");
 }
 /// <summary>
 /// Initializes a new instance of the SSPIException class with the given message and status.
 /// </summary>
 /// <param name="message">A message explaining what part of the system failed.</param>
 /// <param name="errorCode">The error code observed during the failure.</param>
 public CSSPIException(string message, CSecurityStatus errorCode)
 {
     this.message   = message;
     this.errorCode = errorCode;
 }
 /// <summary>
 /// Returns whether or not the status represents an error.
 /// </summary>
 /// <param name="status"></param>
 /// <returns>True if the status represents an error condition.</returns>
 public static bool IsError(this CSecurityStatus status)
 {
     return((uint)status > 0x80000000u);
 }
        /// <summary>
        /// Changes the current thread's security context to impersonate the user of the client.
        /// </summary>
        /// <remarks>
        /// Requires that the security package provided with the server's credentials, as well as the
        /// client's credentials, support impersonation.
        ///
        /// Currently, only one thread may initiate impersonation per security context. Impersonation may
        /// follow threads created by the initial impersonation thread, however.
        /// </remarks>
        /// <returns>A handle to capture the lifetime of the impersonation. Dispose the handle to revert
        /// impersonation. If the handle is leaked, the impersonation will automatically revert at a
        /// non-deterministic time when the handle is finalized by the Garbage Collector.</returns>
        public CImpersonationHandle ImpersonateClient()
        {
            CImpersonationHandle handle;
            CSecurityStatus      status = CSecurityStatus.InternalError;
            bool gotRef = false;

            if (this.Disposed)
            {
                throw new ObjectDisposedException("ServerContext");
            }
            else if (this.Initialized == false)
            {
                throw new InvalidOperationException(
                          "The server context has not been completely initialized."
                          );
            }
            else if (impersonating)
            {
                throw new InvalidOperationException("Cannot impersonate again while already impersonating.");
            }
            else if (this.SupportsImpersonate == false)
            {
                throw new InvalidOperationException(
                          "The ServerContext is using a security package that does not support impersonation."
                          );
            }

            handle = new CImpersonationHandle(this);
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                this.ContextHandle.DangerousAddRef(ref gotRef);
            }
            catch (Exception)
            {
                if (gotRef)
                {
                    this.ContextHandle.DangerousRelease();
                    gotRef = false;
                }

                throw;
            }
            finally
            {
                if (gotRef)
                {
                    status = CContextNativeMethods.ImpersonateSecurityContext(
                        ref this.ContextHandle.rawHandle
                        );

                    this.ContextHandle.DangerousRelease();

                    this.impersonating = true;
                }
            }

            if (status == CSecurityStatus.NoImpersonation)
            {
                throw new CSSPIException("Impersonation could not be performed.", status);
            }
            else if (status == CSecurityStatus.Unsupported)
            {
                throw new CSSPIException("Impersonation is not supported by the security context's Security Support Provider.", status);
            }
            else if (status != CSecurityStatus.OK)
            {
                throw new CSSPIException("Failed to impersonate the client", status);
            }

            return(handle);
        }