1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 //
5 // Presharp uses the c# pragma mechanism to supress its warnings.
6 // These are not recognised by the base compiler so we need to explictly
7 // disable the following warnings. See http://winweb/cse/Tools/PREsharp/userguide/default.asp
8 // for details.
9 //
10 #pragma warning disable 1634, 1691      // unknown message, unknown pragma
11 
12 namespace System.IdentityModel.Selectors
13 {
14     using System;
15     using System.Runtime.InteropServices;
16     using System.Threading;
17     using System.Security;
18     using System.Runtime.ConstrainedExecution;
19     using System.Runtime.CompilerServices;
20     using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace;
21 
22 
23     //
24     // For common & resources
25     //
26     using Microsoft.InfoCards;
27 
28     //
29     // Summary:
30     //  Wraps and manages the lifetime of a native crypto handle passed back from the native InfoCard API.
31     //
32     internal abstract class CryptoHandle : IDisposable
33     {
34         bool m_isDisposed;
35         InternalRefCountedHandle m_internalHandle;
36 
37         //
38         // Summary:
39         //  Creates a new CryptoHandle. ParamType has information as to what
40         //  nativeParameters has to be marshaled into.
41         //
CryptoHandle(InternalRefCountedHandle nativeHandle, DateTime expiration, IntPtr nativeParameters, Type paramType)42         protected CryptoHandle(InternalRefCountedHandle nativeHandle, DateTime expiration, IntPtr nativeParameters, Type paramType)
43         {
44             m_internalHandle = nativeHandle;
45 
46             m_internalHandle.Initialize(expiration, Marshal.PtrToStructure(nativeParameters, paramType));
47         }
48 
49         //
50         // Summary:
51         //  This constructor creates a new CryptoHandle instance with the same InternalRefCountedHandle and adds
52         //  a ref count to that InternalRefCountedHandle.
53         //
CryptoHandle(InternalRefCountedHandle internalHandle)54         protected CryptoHandle(InternalRefCountedHandle internalHandle)
55         {
56             m_internalHandle = internalHandle;
57             m_internalHandle.AddRef();
58         }
59 
60         public InternalRefCountedHandle InternalHandle
61         {
62             get
63             {
64                 ThrowIfDisposed();
65                 return m_internalHandle;
66             }
67         }
68 
69 
70 
71         public DateTime Expiration
72         {
73             get
74             {
75                 ThrowIfDisposed();
76                 return m_internalHandle.Expiration;
77             }
78         }
79 
80         public object Parameters
81         {
82             get
83             {
84                 ThrowIfDisposed();
85                 return m_internalHandle.Parameters;
86             }
87         }
88 
89         //
90         // Summary:
91         //  Creates a new CryptoHandle with same InternalRefCountedCryptoHandle.
92         //
Duplicate()93         public CryptoHandle Duplicate()
94         {
95             ThrowIfDisposed();
96             return OnDuplicate();
97         }
98 
99 
100         //
101         // Summary:
102         //  Allows subclasses to create a duplicate of their particular class.
103         //
OnDuplicate()104         protected abstract CryptoHandle OnDuplicate();
105 
ThrowIfDisposed()106         protected void ThrowIfDisposed()
107         {
108             if (m_isDisposed)
109             {
110                 throw IDT.ThrowHelperError(new ObjectDisposedException(SR.GetString(SR.ClientCryptoSessionDisposed)));
111             }
112         }
113 
Dispose()114         public void Dispose()
115         {
116             if (m_isDisposed)
117             {
118                 return;
119             }
120 
121             m_internalHandle.Release();
122             m_internalHandle = null;
123             m_isDisposed = true;
124         }
125 
126         //
127         // Summary:
128         //  Given a pointer to a native cryptosession this method creates the appropriate CryptoHandle type.
129         //
Create(InternalRefCountedHandle nativeHandle)130         static internal CryptoHandle Create(InternalRefCountedHandle nativeHandle)
131         {
132             CryptoHandle handle = null;
133 
134             bool mustRelease = false;
135             RuntimeHelpers.PrepareConstrainedRegions();
136             try
137             {
138                 nativeHandle.DangerousAddRef(ref mustRelease);
139                 RpcInfoCardCryptoHandle hCrypto =
140                     (RpcInfoCardCryptoHandle)Marshal.PtrToStructure(nativeHandle.DangerousGetHandle(),
141                                                                      typeof(RpcInfoCardCryptoHandle));
142                 DateTime expiration = DateTime.FromFileTimeUtc(hCrypto.expiration);
143 
144                 switch (hCrypto.type)
145                 {
146                     case RpcInfoCardCryptoHandle.HandleType.Asymmetric:
147                         handle = new AsymmetricCryptoHandle(nativeHandle, expiration, hCrypto.cryptoParameters);
148                         break;
149                     case RpcInfoCardCryptoHandle.HandleType.Symmetric:
150                         handle = new SymmetricCryptoHandle(nativeHandle, expiration, hCrypto.cryptoParameters);
151                         break;
152                     case RpcInfoCardCryptoHandle.HandleType.Transform:
153                         handle = new TransformCryptoHandle(nativeHandle, expiration, hCrypto.cryptoParameters);
154                         break;
155                     case RpcInfoCardCryptoHandle.HandleType.Hash:
156                         handle = new HashCryptoHandle(nativeHandle, expiration, hCrypto.cryptoParameters);
157                         break;
158                     default:
159                         IDT.DebugAssert(false, "Invalid crypto operation type");
160                         throw IDT.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.GeneralExceptionMessage)));
161                 }
162 
163                 return handle;
164 
165             }
166             finally
167             {
168                 if (mustRelease)
169                 {
170                     nativeHandle.DangerousRelease();
171                 }
172             }
173         }
174 
175 
176     }
177 
178     //
179     // Summary:
180     //  This class manages the lifetime of a native crypto handle through ref counts.  Any number of CryptoHandles
181     //  may refer to a single InternalRefCountedHandle, but once they are all disposed this object will dispose
182     //  itself as well.
183     //
184     internal class InternalRefCountedHandle : SafeHandle
185     {
186         int m_refcount = 0;
187         DateTime m_expiration;
188         object m_parameters = null;
189 
190         [DllImport("infocardapi.dll",
191                     EntryPoint = "CloseCryptoHandle",
192                     CharSet = CharSet.Unicode,
193                     CallingConvention = CallingConvention.StdCall,
194                     ExactSpelling = true,
195                     SetLastError = true)]
196         [SuppressUnmanagedCodeSecurity]
197         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
CloseCryptoHandle([In] IntPtr hKey)198         private static extern bool CloseCryptoHandle([In] IntPtr hKey);
199 
InternalRefCountedHandle()200         private InternalRefCountedHandle()
201             : base(IntPtr.Zero, true)
202         {
203             m_refcount = 1;
204 
205         }
206 
Initialize(DateTime expiration, object parameters)207         public void Initialize(DateTime expiration, object parameters)
208         {
209             m_expiration = expiration;
210             m_parameters = parameters;
211         }
212 
213 
214         //
215         // Summary:
216         //  The deserialized parameters specific to a particular type of CryptoHandle.
217         //
218         public object Parameters
219         {
220             get
221             {
222                 ThrowIfInvalid();
223                 return m_parameters;
224             }
225         }
226 
227         //
228         // Summary:
229         //  The expiration of this CryptoHandle
230         //
231         public DateTime Expiration
232         {
233             get
234             {
235                 ThrowIfInvalid();
236                 return m_expiration;
237             }
238         }
239 
AddRef()240         public void AddRef()
241         {
242             ThrowIfInvalid();
243             Interlocked.Increment(ref m_refcount);
244         }
245 
Release()246         public void Release()
247         {
248             ThrowIfInvalid();
249             int refcount = Interlocked.Decrement(ref m_refcount);
250             if (0 == refcount)
251             {
252                 Dispose();
253             }
254         }
255 
ThrowIfInvalid()256         private void ThrowIfInvalid()
257         {
258             if (IsInvalid)
259             {
260                 throw IDT.ThrowHelperError(new ObjectDisposedException("InternalRefCountedHandle"));
261             }
262         }
263         public override bool IsInvalid
264         {
265             get
266             {
267                 return (IntPtr.Zero == base.handle);
268             }
269         }
270 
271 
ReleaseHandle()272         protected override bool ReleaseHandle()
273         {
274 #pragma warning suppress 56523
275             return CloseCryptoHandle(base.handle);
276         }
277 
278     }
279 }
280