예제 #1
0
        /// <summary>
        /// Second part of 2FA.
        /// </summary>
        /// <param name="user">User information.</param>
        /// <param name="certificate">User <see cref="X509Certificate2"/> public certificate in raw form.</param>
        /// <param name="usersDb">Enigma's user database.</param>
        /// <param name="crlListPath">Path on FS to CRL directory.</param>
        /// <param name="caTrustListPath">Path on FS to CA trust list.</param>
        public void LoginPartTwo(User user, byte[] certificate, UserDatabase usersDb, string crlListPath, string caTrustListPath)
        {
            var userCert = new X509Certificate2(certificate);
            var publicKeyFromCertificate = ((RSACryptoServiceProvider)userCert.PublicKey.Key).ExportParameters(false);

            // compare user public RSA key from x509 public certificate with a public RSA key that was stored when user first registered
            if (!RsaAlgorithm.CompareKeys(publicKeyFromCertificate, RsaAlgorithm.ExportParametersFromXmlString(user.PublicKey, false)))
            {
                throw new Exception("Wrong certificate used.");
            }
            // if wrong file is loaded instead of the x509 public certificate in PEM format
            if (userCert == null)
            {
                throw new Exception("Certificate error.");
            }

            // update user last login time and reset atttemp count
            usersDb.UpdateLoginTime(user, DateTime.Now.ToString("dddd, MMM dd yyyy, hh:mm:ss"));

            // reset login attempt if necessary
            if (user.LoginAttempt != 0)
            {
                usersDb.ResetLoginAttempts(user);
            }

            //if (CertificateValidator.VerifyCertificate(userCert, out var errorMsg, false) == false)
            //{
            //    throw new Exception(errorMsg);
            //}

            // Check if the certificate has been revoked and set Revoked value if necessary.
            if (CertificateValidator.VerifyCertificateRevocationStatus(userCert, crlListPath, caTrustListPath))
            {
                usersDb.SetCertificateRevokeStatus(user);
                //throw new Exception("Certificate has been revoked.");
            }
        }
예제 #2
0
        /// <summary>
        /// Registers a new user if the register policy are met.
        /// </summary>
        /// <param name="username">Users account username.</param>
        /// <param name="password">Users password.</param>
        /// <param name="certificateFilePath">Path on FS to users certificate.</param>
        public void Register(ref string username, string password, string certificateFilePath, bool skipPasswordStrengthCheck = false)
        {
            if (username.Length > 25)
            {
                throw new Exception("Usernames can't have more than 25 characters.");
            }

            if (!skipPasswordStrengthCheck && password.Contains(username))
            {
                throw new Exception("Password cannot contain your username.");
            }

            // Probability of repetition of this do-while loop is low.
            do
            {
                // Add a random 4-digit number to users username.
                var csprng = new SecureRandom(new DigestRandomGenerator(new Sha256Digest()));
                csprng.SetSeed(DateTime.Now.Ticks); // TODO: is this a good seed value?
                var suffix = "#" + csprng.Next(1_000, 9_999).ToString();

                // If username collision occurs, generate new 4-digit suffix.
                if (data.GetUser(username + suffix) != null)
                {
                    continue;
                }
                else
                {
                    username += suffix;
                    break;
                }
            } while (true);

            // Check if a password used some of the most common passwords discovered in various data breaches.
            if (!skipPasswordStrengthCheck && PasswordAdvisor.CommonPasswordCheck(password, commonPasswordsPath))
            {
                throw new Exception("This password is not allowed. Please try again.");
            }

            // Check password strength.
            if (!skipPasswordStrengthCheck && !PasswordAdvisor.IsPasswordStrong(password, out var passwordStrength, false))
            {
                throw new Exception($"Password is deemed {passwordStrength}. Please try again.");
            }

            var cert = new X509Certificate2(certificateFilePath);

            // Check if key length is >= 2048 bits.
            if (CertificateValidator.VerifyCertificateKeyLength(cert) == false)
            {
                throw new Exception("Key length has to be at least 2048 bits.");
            }

            // Checks if the certificate has expired and if it is issued by a proper root certificate.
            if (CertificateValidator.VerifyCertificate(cert, caTrustListPath, out var errorMsg, true) == false)
            {
                throw new Exception(errorMsg);
            }

            // Check if the certificate is revoked.
            if (CertificateValidator.VerifyCertificateRevocationStatus(cert, crlListPath, caTrustListPath) == true)
            {
                throw new Exception("Certificate has been revoked.");
            }

            // Check if certificate has a proper key usage set.
            if (CertificateValidator.VerifyKeyUsage(cert) == false)
            {
                throw new Exception("Certificate must have 'digitalSignature' and 'keyEncipherment' set as it's key usage.");
            }
        }