source: trunk/CrypP2P/Helper/PAPCertificate.cs @ 1458

Last change on this file since 1458 was 1458, checked in by Paul Lelgemann, 12 years ago
  • Removed unused references and using statement in CrypP2P, PeerToPeer, PeerToPeerBaseProxy

+ Skeleton for P2PEditor

File size: 20.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Security.Cryptography.X509Certificates;
5using System.IO;
6using Cryptool.PluginBase;
7
8/*
9 * EVERYTHING UNTESTED AND NOT READY!!!
10 */
11
12namespace Cryptool.P2P.Helper
13{
14    public static class PAPCertificate
15    {
16        #region Variables
17
18        /// <summary>
19        /// You can only use the P@P-network by using this user name!!!
20        /// All certificates, which are necessary for using the P@P-P2P-Network, are
21        /// registered with this user name.
22        /// </summary>
23        public const string CERTIFIED_PEER_NAME = "CrypTool2"; //"pap0001"; //"CT_PAP_User";
24        public const string CERTIFICATE_DIRECTORY = "pap_certificates";
25
26        private static string sCertPath;
27        /// <summary>
28        /// only set the application path - without certificate
29        /// directory or a specific certificate file name!
30        /// </summary>
31        public static string CertPath
32        {
33            get { return sCertPath; }
34            private set
35            {
36                string combindedCertPath = Path.Combine(value, CERTIFICATE_DIRECTORY);
37                if (Directory.Exists(combindedCertPath))
38                    sCertPath = combindedCertPath;
39                else
40                    throw (new DirectoryNotFoundException("Path: " + combindedCertPath + " not found"));
41            }
42        }
43
44        //private const string CERT_USER_SUBJECT = "CN=pap0001@pap.de@pap0001@.*, O=Peers@Play, S=None, C=NA";
45        private const string CERT_USER_FILE_NAME = "CrypTool2.pfx"; //"pap0001.p12"; //ct2_user_pap.cer
46        private const string CERT_USER_PASSWORD = "ct2"; //"test"; //CT2p@pC3rt1f1cat10n
47        private const string CERT_USER_ISSUER = "P@P project";
48        private const string CERT_USER_SERIAL = "1E"; //"0D";
49
50        private const string CERT_PAP_FILE_NAME = "pap.cer";
51        private const string CERT_PAP_PASSWORD = "test";
52        private const string CERT_PAP_ISSUER = "P@P project";
53        private const string CERT_PAP_SERIAL = "37cbb8163698c48845e9d5c80e3496b1";
54
55        private const string CERT_OPA_FILE_NAME = "opa.vs.uni-due.de.cer";
56        private const string CERT_OPA_PASSWORD = "";
57        private const string CERT_OPA_ISSUER = "opa.vs.uni-due.de";
58        private const string CERT_OPA_SERIAL = "2FB799C15BAE2FB74FDB72DD0329196A";
59
60        private const string CERT_SERVER_CA_FILE_NAME = "ServerCA.cer";
61        private const string CERT_SERVER_CA_PASSWORD = "";
62        private const string CERT_SERVER_CA_ISSUER = "PAP Server CA";
63        private const string CERT_SERVER_CA_SERIAL = "23440A89B21FA7B84ADDB59DA494F79B";
64
65        private const X509FindType PAP_FIND_TYPE = X509FindType.FindBySerialNumber;
66        // here have to be at least two certificate (PAP Server CA, P@P project)
67        private const StoreName CERT_STORE_ROOT = StoreName.Root;
68        private const StoreLocation CERT_STORE_LOCATION = StoreLocation.CurrentUser;
69        // here has to be one certificate (User certificate)
70        private const StoreName CERT_STORE_USER = StoreName.My;
71
72        #endregion
73
74        #region VERY PAP-SPECIFIC CERTIFICATE METHODS
75
76        public enum PAP_Certificates
77        {
78            Server_CA,
79            Opa,
80            Pap,
81            User
82        }
83
84        /// <summary>
85        /// Checks if all neccessary certificates were installed, otherwise trying to
86        /// install all missing certificates. Returns true if everything worked fine.
87        /// </summary>
88        /// <param name="sPath">only the path of the running application, not the
89        /// certificate direction or a specific filename!!! Everything else will
90        /// be combined internally!!!</param>
91        /// <returns></returns>
92        public static bool CheckAvailabilityAndInstallMissingCertificates(string sPath)
93        {
94            List<PAP_Certificates> lstMissingCerts = new List<PAP_Certificates>();
95            lstMissingCerts = CheckAvailabilityOfPAPCertificates(sPath);
96            return InstallMissingCertificates(lstMissingCerts, sPath);
97        }
98
99        /// <summary>
100        /// Checks if all neccessary certificates were installed, otherwise it returns a
101        /// list with all missing certificates
102        /// </summary>
103        /// <param name="sPath">only the path of the running application, not the
104        /// certificate direction or a specific filename!!! Everything else will
105        /// be combined internally!!!</param>
106        /// <returns></returns>
107        public static List<PAP_Certificates> CheckAvailabilityOfPAPCertificates(string sPath)
108        {
109            CertPath = sPath;
110            List<PAP_Certificates> retLst = new List<PAP_Certificates>();
111            X509Certificate2Collection certColl;
112
113            /* BEGIN: Checking availablity of the three root certificates */
114
115            // Wacker 27.02.2010: Removed checking for Server and OPA (operator-SSL) certificates; These are only needed if
116            // we want to get a new certificate online - a feature which is not implmented now. When this feature is
117            // implemented, just uncommentd the following lines
118
119            //certColl = FindCertificates(CERT_STORE_ROOT, CERT_STORE_LOCATION,
120            //    PAP_FIND_TYPE, CERT_SERVER_CA_SERIAL, true);
121            //if (certColl.Count == 0)
122            //    retLst.Add(PAP_Certificates.Server_CA);
123
124            //certColl = FindCertificates(CERT_STORE_ROOT, CERT_STORE_LOCATION,
125            //    PAP_FIND_TYPE, CERT_OPA_SERIAL, true);
126            //if (certColl.Count == 0)
127            //    retLst.Add(PAP_Certificates.Opa);
128
129            certColl = FindCertificates(CERT_STORE_ROOT, CERT_STORE_LOCATION,
130                PAP_FIND_TYPE, CERT_PAP_SERIAL, true);
131            if (certColl.Count == 0)
132                retLst.Add(PAP_Certificates.Pap);
133            /* END: Checking availablity of the three root certificates */
134
135            // Check user certificate availability
136            certColl = FindCertificates(CERT_STORE_USER, CERT_STORE_LOCATION,
137                PAP_FIND_TYPE, CERT_USER_SERIAL, true);
138            if (certColl.Count == 0)
139                retLst.Add(PAP_Certificates.User);
140
141            return retLst;
142        }
143
144        /// <summary>
145        /// Installs all certificates, which are specified in the parameter list.
146        /// Returns true, if everything works fine
147        /// </summary>
148        /// <param name="installList">a list of all certificates, which you want to install</param>
149        /// <param name="sPath">only the path of the running application, not the
150        /// certificate direction or a specific filename!!! Everything else will
151        /// be combined internally!!!</param>
152        /// <returns></returns>
153        public static bool InstallMissingCertificates(List<PAP_Certificates> installList, string sPath)
154        {
155            bool intermediateResult = true;
156            bool actualResult = true;
157
158            CertPath = sPath;
159
160            foreach (PAP_Certificates papCert in installList)
161            {
162                switch (papCert)
163                {
164                    case PAP_Certificates.Server_CA:
165                        intermediateResult = InstallCertificate(CERT_STORE_ROOT, CERT_STORE_LOCATION,
166                            Path.Combine(CertPath, CERT_SERVER_CA_FILE_NAME), CERT_SERVER_CA_PASSWORD);
167                        break;
168                    case PAP_Certificates.Opa:
169                        intermediateResult = InstallCertificate(CERT_STORE_ROOT, CERT_STORE_LOCATION,
170                            Path.Combine(CertPath, CERT_OPA_FILE_NAME), CERT_OPA_PASSWORD);
171                        break;
172                    case PAP_Certificates.Pap:
173                        intermediateResult = InstallCertificate(CERT_STORE_ROOT, CERT_STORE_LOCATION,
174                            Path.Combine(CertPath, CERT_PAP_FILE_NAME), CERT_PAP_PASSWORD);
175                        break;
176                    case PAP_Certificates.User:
177                        intermediateResult = InstallCertificate(CERT_STORE_USER, CERT_STORE_LOCATION,
178                            Path.Combine(CertPath, CERT_USER_FILE_NAME), CERT_USER_PASSWORD);
179                        break;
180                    default:
181                        break;
182                }
183                actualResult = actualResult && intermediateResult;
184            }
185            return actualResult;
186        }
187
188        #endregion
189
190        #region Common Certificate Operations (Find and Install Certs)
191
192        /// <summary>
193        /// Searches for certificates in the given Store with the given FindType and value
194        /// </summary>
195        /// <param name="storeName">Name of the store</param>
196        /// <param name="storeLocation">Location of the store</param>
197        /// <param name="findType">choose which attribute of the installed cert's should be compare with the given value</param>
198        /// <param name="findValue">value, which should be exactly in the chosen FindType of an installed certificate</param>
199        /// <param name="onlyValidCerts">only valid certificates (not outdated, revocated, etc.) will be considered.</param>
200        /// <returns>a list of all certificates, who satisfy the search attributes</returns>
201        private static X509Certificate2Collection FindCertificates(StoreName storeName, StoreLocation storeLocation, X509FindType findType, object findValue, bool onlyValidCerts)
202        {
203            X509Certificate2Collection findedCertCol = null;
204            X509Store store = new X509Store(storeName, storeLocation);
205            try
206            {
207                store.Open(OpenFlags.ReadOnly);
208                findedCertCol = store.Certificates.Find(findType, findValue, onlyValidCerts);
209            }
210            catch (Exception)
211            {
212
213                throw;
214            }
215            finally
216            {
217                store.Close();
218            }
219
220            return findedCertCol;
221        }
222
223        /// <summary>
224        /// Installs a given certificate if it is already valid and not installed yet
225        /// </summary>
226        /// <param name="storeName">Name of the store</param>
227        /// <param name="storeLocation">Location of the store</param>
228        /// <param name="sCertPath">Whole certification path and filename</param>
229        /// <param name="sCertPassword">if necessary, you have to declare a password. Otherwise use ""</param>
230        private static bool InstallCertificate(StoreName storeName, StoreLocation storeLocation, string sCertPath, string sCertPassword)
231        {
232            bool ret = false;
233
234            if (File.Exists(sCertPath))
235            {
236                X509Store store = new X509Store(storeName, storeLocation);
237                try
238                {
239                    /* Verification of certifates failed every time - no idea why */
240                    //if (cert.Verify())
241                    //{
242                    X509Certificate2 cert = new X509Certificate2(sCertPath, sCertPassword);
243                    store.Open(OpenFlags.ReadWrite);
244                    store.Add(cert);
245                    store.Close();
246                    ret = true;
247                    //}
248                    //else
249                    //{
250                    //    throw (new Exception("Installing Certificate " + cert.SubjectName.Name + " wasn't possible, because Certificate isn't valid anymore"));
251                    //}
252                }
253                catch (Exception ex)
254                {
255                    throw (new Exception("Installation of " + sCertPath + " certificate wasn't possible", ex));
256                }
257                finally
258                {
259                    store.Close();
260                }
261            }
262            return ret;
263        }
264
265        #endregion
266
267        #region (currently not used) PAP specific stuff (eMail Address registered certificates, etc.)
268
269        /// <summary>
270        /// Will search for the root certificate in the windows certificate store.
271        /// </summary>
272        /// <returns>The root certificate or null on error</returns>
273        public static X509Certificate2Collection getRootCertificate()
274        {
275            X509Certificate2Collection root = FindCertificates(CERT_STORE_ROOT, CERT_STORE_LOCATION, X509FindType.FindBySerialNumber, CERT_PAP_SERIAL, true);
276            return root;
277        }
278
279        /// <summary>
280        /// Gives back an X509Certificate2 from an given email address (hashed value)
281        /// </summary>
282        /// <param name="email">the email</param>
283        /// <returns>the searched certificate</returns>
284        public static X509Certificate2 GetCertificateWithMail(String email)
285        {
286            try
287            {
288                String fileName = GetHash(email);
289                X509Certificate2Collection col = FindCertificates(StoreName.My, StoreLocation.CurrentUser, X509FindType.FindByIssuerName, CERT_PAP_ISSUER, true);
290                foreach (X509Certificate2 cert in col)
291                {
292                    if (cert.Subject.Contains(fileName))
293                    {
294                        return cert;
295                    }
296                }
297                return null;
298            }
299            catch
300            {
301                return null;
302            }
303        }
304
305        /// <summary>
306        /// Creates an crypted string from an ordinary
307        /// </summary>
308        /// <param name="str">the ordinary string</param>
309        /// <returns>an coded string</returns>
310        public static String GetHash(String str)
311        {
312            str = str.ToLower();
313            System.Security.Cryptography.SHA1 sec = new System.Security.Cryptography.SHA1CryptoServiceProvider();
314            Encoding encoding = Encoding.Unicode;
315            byte[] insertion = encoding.GetBytes(str);
316            byte[] hash = sec.ComputeHash(insertion);
317            String result = BitConverter.ToString(hash);//Convert.ToBase64String(hash);
318            result = result.Substring(result.Length / 2 + 1);
319            return result;
320        }
321
322        #endregion
323
324        #region PickCertificate (currently not used)
325        /// <summary>
326        /// Let the user choose a certificate from given location and store name
327        /// </summary>
328        /// <param name="location">The location</param>
329        /// <param name="name">The store name</param>
330        public static void PickCertificate(StoreLocation location, StoreName name)
331        {
332            X509Certificate2 MyCertificate;
333            X509Store store = new X509Store(name, location);
334            try
335            {
336                store.Open(OpenFlags.ReadOnly);
337
338                // Pick a certificate from the store
339                MyCertificate = X509Certificate2UI.SelectFromCollection(store.Certificates, "P@P certificates", "Please select your certificate", X509SelectionFlag.SingleSelection)[0];
340
341                // Comment next line to enable selection of an invalid certificate
342                ValidateCert(MyCertificate);
343
344                //MyCertificateSerialNumber = MyCertificate.SerialNumber;
345            }
346            catch (Exception ex)
347            {
348                MyCertificate = null;
349                throw (new Exception("Certificate not valid", ex));
350            }
351            finally { store.Close(); }
352        }
353        #endregion
354
355        #region ValidateCert (currently not used)
356        /// <summary>
357        /// Validates a certificate according to P@P-rules
358        /// </summary>
359        /// <exception cref="SNALCertificateNotValidException"></exception>
360        /// <exception cref="ArgumentNullException"></exception>
361        /// <param name="cert">Certificate to validate</param>
362        public static void ValidateCert(X509Certificate2 cert)
363        {
364            if (cert == null)
365            {
366                throw new ArgumentNullException("cert");
367            }
368
369            X509Chain chain = new X509Chain();
370
371            // check entire chain for revocation
372            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
373
374            // TODO: Check Online
375            chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
376
377            // timeout for online revocation list
378            chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 30);
379
380            // TODO: Revocation unknown allowed
381            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
382
383            // Check chain
384            chain.Build(cert);
385
386            // If there was an error or no root CA is given throw exception
387            if (chain.ChainStatus.Length != 0 || chain.ChainElements.Count != 2)
388            {
389                throw new Exception("Certificates chain not valid!");
390            }
391
392            // Check root certificate
393            if (chain.ChainElements[1].Certificate.SerialNumber.ToLower() != CERT_PAP_SERIAL.ToLower())
394            {
395                throw new Exception("Certificates root CA not valid!");
396            }
397        }
398        #endregion
399
400        /// <summary>
401        /// Checks if all certificates for using the pap p2p system are installed.
402        /// Otherwise it tries to install the missing certificates. If all operations
403        /// succeed, return value is true. Only when value is true, you can try
404        /// to initialize the PAP System.
405        /// </summary>
406        /// <returns>If all operations succeed, return value is true. Only when value
407        /// is true, you can try to initialize the PAP System.</returns>
408        public static bool CheckAndInstallPAPCertificates()
409        {
410            bool retValue = false;
411
412            // get exe directory, because there resides the certificate directory
413            System.Reflection.Assembly assemb = System.Reflection.Assembly.GetEntryAssembly();
414            string applicationDir = System.IO.Path.GetDirectoryName(assemb.Location);
415            // check if all necessary certs are installed
416            P2PManager.Instance.GuiLogMessage("Check installation of all certificates, which are necessary to run the p2p system", NotificationLevel.Info);
417            List<PAPCertificate.PAP_Certificates> lstMissingCerts = PAPCertificate.CheckAvailabilityOfPAPCertificates(applicationDir);
418            if (lstMissingCerts.Count == 0)
419            {
420                //GuiLogMessage("All neccessary p2p certificates are installed.", NotificationLevel.Info);
421                retValue = true;
422            }
423            else
424            {
425                StringBuilder sbMissingCerts = new StringBuilder();
426                for (int i = 0; i < lstMissingCerts.Count; i++)
427                {
428                    sbMissingCerts.AppendLine(Enum.GetName(typeof(PAPCertificate.PAP_Certificates), lstMissingCerts[i]));
429                }
430                P2PManager.Instance.GuiLogMessage("Following certificates are missing. They will be installed now.\n" + sbMissingCerts.ToString(), NotificationLevel.Info);
431
432                // try/catch neccessary because the CT-Editor doesn't support the whole exception display process (e.g. shows only "unknown error.")
433                try
434                {
435                    if (PAPCertificate.InstallMissingCertificates(lstMissingCerts, applicationDir))
436                    {
437                        P2PManager.Instance.GuiLogMessage("Installation of all missing certificates was successful.", NotificationLevel.Info);
438                        retValue = true;
439                    }
440                    else
441                    {
442                        P2PManager.Instance.GuiLogMessage("No/not all missing certificates were installed successful.", NotificationLevel.Error);
443                    }
444                }
445                catch (Exception ex)
446                {
447                    P2PManager.Instance.GuiLogMessage("Error occured while installing certificates. Exception: " + ex.ToString(), NotificationLevel.Error);
448                }
449            }
450            return retValue;
451        }
452    }
453}
Note: See TracBrowser for help on using the repository browser.