1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 namespace System.IdentityModel
6 {
7     using System.ComponentModel;
8     using System.Runtime.InteropServices;
9     using System.Runtime.CompilerServices;
10     using System.Runtime.ConstrainedExecution;
11     using System.Security.Cryptography;
12     using System.ServiceModel.Diagnostics;
13     using Microsoft.Win32.SafeHandles;
14 
15     class SafeProvHandle : SafeHandleZeroOrMinusOneIsInvalid
16     {
SafeProvHandle()17         SafeProvHandle() : base(true) { }
18 
19         // 0 is an Invalid Handle
SafeProvHandle(IntPtr handle)20         SafeProvHandle(IntPtr handle)
21             : base(true)
22         {
23             DiagnosticUtility.DebugAssert(handle == IntPtr.Zero, "SafeProvHandle constructor can only be called with IntPtr.Zero.");
24             SetHandle(handle);
25         }
26 
27         internal static SafeProvHandle InvalidHandle
28         {
29             get { return new SafeProvHandle(IntPtr.Zero); }
30         }
31 
ReleaseHandle()32         protected override bool ReleaseHandle()
33         {
34             // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call.
35 #pragma warning suppress 56523 // We are not interested in throwing an exception here if CloseHandle fails.
36             return NativeMethods.CryptReleaseContext(handle, 0);
37         }
38     }
39 
40     class SafeKeyHandle : SafeHandleZeroOrMinusOneIsInvalid
41     {
42         SafeProvHandle provHandle = null;
43 
SafeKeyHandle()44         SafeKeyHandle() : base(true) { }
45 
46         // 0 is an Invalid Handle
SafeKeyHandle(IntPtr handle)47         SafeKeyHandle(IntPtr handle)
48             : base(true)
49         {
50             DiagnosticUtility.DebugAssert(handle == IntPtr.Zero, "SafeKeyHandle constructor can only be called with IntPtr.Zero.");
51             SetHandle(handle);
52         }
53 
54         internal static SafeKeyHandle InvalidHandle
55         {
56             get { return new SafeKeyHandle(IntPtr.Zero); }
57         }
58 
ReleaseHandle()59         protected override bool ReleaseHandle()
60         {
61             // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call.
62 #pragma warning suppress 56523 // We are not interested in throwing an exception here if CloseHandle fails.
63             bool ret = NativeMethods.CryptDestroyKey(handle);
64             if (this.provHandle != null)
65             {
66                 this.provHandle.DangerousRelease();
67                 this.provHandle = null;
68             }
69             return ret;
70         }
71 
SafeCryptImportKey(SafeProvHandle provHandle, void* pbDataPtr, int cbData)72         internal static unsafe SafeKeyHandle SafeCryptImportKey(SafeProvHandle provHandle, void* pbDataPtr, int cbData)
73         {
74             bool b = false;
75             int err = 0;
76             SafeKeyHandle keyHandle = null;
77             RuntimeHelpers.PrepareConstrainedRegions();
78             try
79             {
80                 provHandle.DangerousAddRef(ref b);
81             }
82             catch (Exception e)
83             {
84                 if (System.Runtime.Fx.IsFatal(e))
85                     throw;
86 
87                 if (b)
88                 {
89                     provHandle.DangerousRelease();
90                     b = false;
91                 }
92                 if (!(e is ObjectDisposedException))
93                     throw;
94             }
95             finally
96             {
97                 if (b)
98                 {
99                     b = NativeMethods.CryptImportKey(provHandle, pbDataPtr, (uint)cbData, IntPtr.Zero, 0, out keyHandle);
100                     if (!b)
101                     {
102                         err = Marshal.GetLastWin32Error();
103                         provHandle.DangerousRelease();
104                     }
105                     else
106                     {
107                         // Take ownership of AddRef.  Will Release at Close.
108                         keyHandle.provHandle = provHandle;
109                     }
110                 }
111             }
112 
113             if (!b)
114             {
115                 Utility.CloseInvalidOutSafeHandle(keyHandle);
116                 string reason = (err != 0) ? new Win32Exception(err).Message : String.Empty;
117                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.AESCryptImportKeyFailed, reason)));
118             }
119             return keyHandle;
120         }
121     }
122 }
123