File: SelfSignedCertificate.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (236 lines) | stat: -rw-r--r-- 10,454 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Channels
{
    using System.ComponentModel;
    using System.Runtime;
    using System.Runtime.InteropServices;
    using System.Security.Cryptography.X509Certificates;
    using System.ServiceModel.Diagnostics;

    sealed partial class SelfSignedCertificate : IDisposable
    {
        CertificateHandle cert;
        KeyContainerHandle keyContainer;
        KeyHandle key;
        string keyContainerName;
        string password;
        byte[] exportedBytes;
        X509Certificate2 x509Cert;

        const int CERT_STORE_PROV_MEMORY = 2;
        const int DefaultLifeSpanInYears = 2;

        public static SelfSignedCertificate Create(string name, string password)
        {
            return Create(name,
                        password,
                        DateTime.UtcNow,
                        DateTime.UtcNow.AddYears(DefaultLifeSpanInYears),
                        Guid.NewGuid().ToString());
        }

        public static SelfSignedCertificate Create(
                                    string name,
                                    string password,
                                    DateTime start,
                                    DateTime expire,
                                    string containerName)
        {
            SelfSignedCertificate cert = new SelfSignedCertificate(password, containerName);
            cert.GenerateKeys();
            cert.CreateCertContext(name, start, expire);
            cert.GetX509Certificate();
            Fx.Assert(cert.cert != null, "CertContext could not be created");
            return cert;
        }

        void CreateCertContext(string name, DateTime start, DateTime expire)
        {
            CriticalAllocHandle provInfo;
            CriticalAllocHandle algorithmId;
            provInfo = GetProviderInfo();
            algorithmId = GetSha1AlgorithmId();

            // convert the times to SystemTime structures
            SystemTime beginTime = new SystemTime(start);
            SystemTime expireTime = new SystemTime(expire);

            // convert the name into a X500 name
            CertificateName certName = new CertificateName(name);

            using (CryptoApiBlob nameBlob = certName.GetCryptoApiBlob())
            {
                using (provInfo)
                {
                    using (algorithmId)
                    {
                        cert = CertCreateSelfSignCertificate(keyContainer,
                                                                    nameBlob.GetMemoryForPinning(),
                                                                    SelfSignFlags.None,
                                                                    provInfo,
                                                                    algorithmId,
                                                                    ref beginTime,
                                                                    ref expireTime,
                                                                    IntPtr.Zero);

                        if (cert.IsInvalid)
                            PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(PeerExceptionHelper.GetLastException());

                        //                        if (!CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, provInfo))
                        //                          PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(PeerExceptionHelper.GetLastException());
                        if (!CertSetCertificateContextProperty(cert, CERT_KEY_SPEC_PROP_ID, 0, key))
                            PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(PeerExceptionHelper.GetLastException());
                    }
                }
            }
        }

        public X509Certificate2 GetX509Certificate()
        {
            if (this.x509Cert == null)
            {
                Export();
                this.x509Cert = new X509Certificate2(exportedBytes, password);
            }
            return this.x509Cert;
        }

        void Export()
        {
            Fx.Assert(this.exportedBytes == null, "calling Export twice!!");

            // create a temporary store to export
            using (CertificateStoreHandle store = CertOpenStore(new IntPtr(CERT_STORE_PROV_MEMORY),
                                                                0,
                                                                IntPtr.Zero,
                                                                0,
                                                                IntPtr.Zero))
            {
                // add the certificate to the store
                StoreCertificateHandle addedCert;
                if (!CertAddCertificateContextToStore(store,
                                                cert,
                                                AddDisposition.ReplaceExisting,
                                                out addedCert))
                {
                    int error = Marshal.GetLastWin32Error();
                    Utility.CloseInvalidOutSafeHandle(addedCert);
                    PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(new Win32Exception(error));
                }

                using (addedCert)
                {
                    // Translate to a PFX
                    CryptoApiBlob pfxBlob = new CryptoApiBlob();
                    CryptoApiBlob.InteropHelper blob = pfxBlob.GetMemoryForPinning();
                    GCHandle pfxHandle = GCHandle.Alloc(blob, GCHandleType.Pinned);

                    try
                    {
                        // first figure out the storage space necessary
                        bool result = PFXExportCertStoreEx(store,
                                                            pfxHandle.AddrOfPinnedObject(),
                                                            password,
                                                            IntPtr.Zero,
                                                            PfxExportFlags.ExportPrivateKeys |
                                                            PfxExportFlags.ReportNoPrivateKey |
                                                            PfxExportFlags.ReportNotAbleToExportPrivateKey);

                        if (!result)
                            PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(PeerExceptionHelper.GetLastException());

                        int storageSize = blob.size;
                        pfxHandle.Free();
                        pfxBlob.AllocateBlob(storageSize);
                        blob = pfxBlob.GetMemoryForPinning();
                        pfxHandle = GCHandle.Alloc(blob, GCHandleType.Pinned);

                        // now do the translation
                        if (!PFXExportCertStoreEx(store,
                                                    pfxHandle.AddrOfPinnedObject(),
                                                    password,
                                                    IntPtr.Zero,
                                                    PfxExportFlags.ExportPrivateKeys |
                                                    PfxExportFlags.ReportNoPrivateKey |
                                                    PfxExportFlags.ReportNotAbleToExportPrivateKey))
                            PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(PeerExceptionHelper.GetLastException());
                        exportedBytes = pfxBlob.GetBytes();
                    }
                    finally
                    {
                        if (pfxHandle != null)
                            pfxHandle.Free();

                        if (pfxBlob != null)
                            pfxBlob.Dispose();
                    }
                }
            }
        }

        void GenerateKeys()
        {
            // generate the key container to put the key in
            if (!CryptAcquireContext(out keyContainer,
                                        keyContainerName,
                                        null,
                                        ProviderType.RsaSecureChannel,
                                        ContextFlags.NewKeySet | ContextFlags.Silent))
            {
                int error = Marshal.GetLastWin32Error();
                Utility.CloseInvalidOutSafeHandle(keyContainer);
                keyContainer = null;
                PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(new Win32Exception(error));
            }

            // generate the key
            if (!CryptGenKey(keyContainer,
                                AlgorithmType.KeyExchange,
                                KeyFlags.Exportable2k,
                                out key))
            {
                int error = Marshal.GetLastWin32Error();
                Utility.CloseInvalidOutSafeHandle(key);
                key = null;
                PeerExceptionHelper.ThrowInvalidOperation_PeerCertGenFailure(new Win32Exception(error));
            }
        }

        void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (cert != null)
                    cert.Dispose();
                if (key != null)
                    key.Dispose();
                if (keyContainer != null)
                    keyContainer.Dispose();
                if (keyContainerName != null)
                {
                    CryptAcquireContext(out keyContainer,
                                        keyContainerName,
                                        null,
                                        ProviderType.RsaSecureChannel,
                                        ContextFlags.DeleteKeySet);
                    Utility.CloseInvalidOutSafeHandle(keyContainer);
                }
                GC.SuppressFinalize(this);
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        SelfSignedCertificate(string password, string containerName)
        {
            this.password = password;
            this.keyContainerName = containerName;
        }
    }
}