public X509Certificate2 ConvertCertificate(X509Certificate certificate, AsymmetricCipherKeyPair subjectKeyPair, SecureRandom random, string password) { // Now to convert the Bouncy Castle certificate to a .NET certificate. // See http://web.archive.org/web/20100504192226/http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx // ...but, basically, we create a PKCS12 store (a .PFX file) in memory, and add the public and private key to that. var store = new Pkcs12Store(); // What Bouncy Castle calls "alias" is the same as what Windows terms the "friendly name". string friendlyName = certificate.SubjectDN.ToString(); // Add the certificate. var certificateEntry = new X509CertificateEntry(certificate); store.SetCertificateEntry(friendlyName, certificateEntry); // Add the private key. store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry }); var temporaryPassword = password ?? PasswordUtils.GeneratePassword(12, 6); // Convert it to an X509Certificate2 object by saving/loading it from a MemoryStream. // It needs a password. Since we'll remove this later, it doesn't particularly matter what we use. var stream = new MemoryStream(); store.Save(stream, temporaryPassword.ToCharArray(), random); var convertedCertificate = new X509Certificate2(stream.ToArray(), temporaryPassword, X509KeyStorageFlags.Exportable); return(convertedCertificate); }
public static UserAccount CreateNewUser() { var result = new UserAccount { UserId = Guid.NewGuid(), UserSecret = PasswordUtils.GeneratePassword(), Salt = PasswordUtils.GenerateSalt() }; return(result); }
public static PasswordPrivacyStrategy Create() { return(new PasswordPrivacyStrategy(new PBECipherEncryptor(), PasswordUtils.GeneratePassword())); }
public async Task <IActionResult> Create([FromBody] User user) { if (ModelState.IsValid) { // Invoked with default operation = create param if (!user.Validate(out var validationErrors)) { _response.Errors.Add(Errors.VALIDATION_FAILED, validationErrors); } if (user.AuthKey.Equals(AppConfig.CloudConnectDefaultAuthKey)) { _response.Errors.Add(Errors.RESOURCE_RESERVED, ""); } } else { _response.Errors.Add(Errors.MISSING_BODY, ""); } if (HasErrors()) { return(BadRequest(_response)); } if ((user.HasRole(Models.User.Role.SuperAdmin) || user.HasRole(Models.User.Role.WebApi)) && !CurrentUser().HasRole(Models.User.Role.SuperAdmin)) { // Privilege escalation attempt, shut it down. _response.Errors.Add(Errors.ROLE_ESCALATION_FAILED, ""); return(StatusCode(403, _response)); } long userId = -1; user.CreatedDate = DateTime.Now; user.Source = Models.User.SourceTypes.Local; if (!user.AuthKey.ToLower().Equals(user.AuthKey)) { user.AuthKey = user.AuthKey.ToLower(); _response.Message = Messages.USER_AUTHKEY_FLATTENED; } // Check if the user would like their certificate encrypted. if (user.EncryptCertificate.HasValue && user.EncryptCertificate.Value) { user.CertKey = PasswordUtils.GeneratePassword(48, 6); } else { user.CertKey = null; } var userCertBytes = _cryptoService.IssueUserChain(user.AuthKey, new[] { KeyPurposeID.IdKPClientAuth }, user.CertKey); user.Cert = Convert.ToBase64String(userCertBytes); var existingUser = await Db.SingleAsync <User>(x => x.AuthKey == user.AuthKey); if (existingUser != null) { // Some user already exists with this authkey, let's bail _response.Errors.Add(Errors.CRUD_OPERATION_FAILED, ""); _response.Errors.Add(Errors.VALIDATION_FAILED, new[] { Errors.RESOURCE_EXISTS + ":authKey:" + user.AuthKey }); return(StatusCode(409, _response)); } try { userId = await Db.InsertAsync(user, true); } catch (DbException e) { Logger.LogError(e.Message); _response.Errors.Add(Errors.OBJECT_PERSIST_FAILED, e.Message); } if (HasErrors()) { return(BadRequest(_response)); } user.Id = userId; _response.Result = user; return(Created(Url.RouteUrl("GetUserById", new { id = userId }), _response)); }
Connect(HttpContext httpContext, string nodeKey) { var errors = new Dictionary <string, object>(); // Ok, we aren't already connected. Let's go try talking to the backend and set ourselves up. var request = new RestRequest("unauth/node", Method.POST) { RequestFormat = DataFormat.Json }; var generatedPassword = PasswordUtils.GeneratePassword(24, 0); var body = new UnauthNodeAddRequest { InstallId = _identityProvider.GetGuid().ToString() }; var ownIp = await _ipResolver.Resolve(); body.Ip = ownIp.ToString(); body.Port = httpContext.Connection.LocalPort; body.Protocol = "http"; // TODO: When HTTPs support lands, use -> httpContext.Request.Protocol.ToLower() which returns things like http/1.1 (needs further parsing); body.NodeKey = nodeKey; body.AccessToken = _defaultCloudUserName + ":" + generatedPassword; // This is data about *THIS* specific system being contributed to the cloud/CRM. body.SystemData = _apm.GetAllDetails(); body.Version = AppConfig.version; // Ok, we got the user created. Everything is ready, let's send off the request. var serializedBody = JsonConvert.SerializeObject(body); _logger.LogDebug($"We will be sending: {serializedBody}"); request.AddParameter("application/json; charset=utf-8", serializedBody, ParameterType.RequestBody); // We have to ensure this user actually exists before sending off the request. // First, we need to remove any cached representation. AuthUtils.ClearUserFromCacheIfExists(_cache, _defaultCloudUserName); // Check if the cloud connect user exists already. var user = await _db.SingleAsync <User>(x => x.AuthKey == _defaultCloudUserName) ?? new User(); user.AuthKey = _defaultCloudUserName; user.PasswordSetter = generatedPassword; user.EmailAddress = _defaultCloudUserName + $"@spectero.com"; user.FullName = "Spectero Cloud Management User"; user.Roles = new List <User.Role> { User.Role.SuperAdmin }; user.Source = User.SourceTypes.SpecteroCloud; user.CloudSyncDate = DateTime.Now; user.CertKey = PasswordUtils.GeneratePassword(48, 6); var userCertBytes = _cryptoService.IssueUserChain(user.AuthKey, new[] { KeyPurposeID.IdKPClientAuth }, user.CertKey); user.Cert = Convert.ToBase64String(userCertBytes); // Checks if user existed already, or is being newly created. if (user.Id != 0L) { await _db.UpdateAsync(user); } else { user.CreatedDate = DateTime.Now; await _db.InsertAsync(user); } var response = _restClient.Execute(request); if (response.ErrorException != null) { _logger.LogError(response.ErrorException, "CC: Connect attempt to the Spectero Cloud failed!"); errors.Add(Core.Constants.Errors.FAILED_TO_CONNECT_TO_SPECTERO_CLOUD, response.ErrorMessage); await DeleteCloudUserIfExists(); return(false, errors, HttpStatusCode.ServiceUnavailable, null); } CloudAPIResponse <Node> parsedResponse = null; try { // Parse after error checking. parsedResponse = JsonConvert.DeserializeObject <CloudAPIResponse <Node> >(response.Content); } catch (JsonException e) { // The Cloud Backend fed us bogus stuff, let's bail. _logger.LogError(e, "CC: Connect attempt to the Spectero Cloud failed!"); _logger.LogDebug("Cloud API said: " + response.Content); errors.Add(Core.Constants.Errors.FAILED_TO_CONNECT_TO_SPECTERO_CLOUD, e.Message); await DeleteCloudUserIfExists(); return(false, errors, HttpStatusCode.ServiceUnavailable, parsedResponse); } // ReSharper disable once SwitchStatementMissingSomeCases switch (response.StatusCode) { case HttpStatusCode.Created: await ConfigUtils.CreateOrUpdateConfig(_db, ConfigKeys.CloudConnectStatus, true.ToString()); await ConfigUtils.CreateOrUpdateConfig(_db, ConfigKeys.CloudConnectIdentifier, parsedResponse?.result.id.ToString()); await ConfigUtils.CreateOrUpdateConfig(_db, ConfigKeys.CloudConnectNodeKey, nodeKey); break; default: // Likely a 400 or a 409, just show the response as is. errors.Add(Core.Constants.Errors.FAILED_TO_CONNECT_TO_SPECTERO_CLOUD, ""); errors.Add(Core.Constants.Errors.RESPONSE_CODE, response.StatusCode); errors.Add(Core.Constants.Errors.NODE_PERSIST_FAILED, parsedResponse?.errors); _logger.LogDebug("Cloud API said: " + response.Content); await DeleteCloudUserIfExists(); return(false, errors, HttpStatusCode.ServiceUnavailable, parsedResponse); } return(true, errors, HttpStatusCode.OK, parsedResponse); }
public void Up() { var instanceId = Guid.NewGuid().ToString(); long viablePasswordCost = _config.PasswordCostLowerThreshold; var specteroCertKey = ""; X509Certificate2 specteroCertificate = null; X509Certificate2 ca = null; var localIPs = Utility.GetLocalIPs(_config.IgnoreRFC1918); if (!_db.TableExists <Configuration>()) { _db.CreateTable <Configuration>(); _logger.LogDebug("Firstrun: Creating Configurations table and inserting default values"); // Identity _db.Insert(new Configuration { Key = ConfigKeys.SystemIdentity, Value = instanceId }); // Schema version _db.Insert(new Configuration { Key = ConfigKeys.SchemaVersion, Value = AppConfig.version }); // Cloud Connectivity _db.Insert(new Configuration { Key = ConfigKeys.CloudConnectStatus, Value = false.ToString() }); // HTTP proxy var httpSkeleton = Defaults.HTTP.Value; var proposedListeners = localIPs.Select(ip => Tuple.Create(ip.ToString(), 10240)) .ToList(); if (proposedListeners.Count > 0) { httpSkeleton.listeners = proposedListeners; } _db.Insert(new Configuration { Key = ConfigKeys.HttpConfig, Value = JsonConvert.SerializeObject(httpSkeleton) }); // Password Hashing _logger.LogDebug("Firstrun: Calculating optimal password hashing cost."); viablePasswordCost = AuthUtils.GenerateViableCost(_config.PasswordCostCalculationTestTarget, _config.PasswordCostCalculationIterations, _config.PasswordCostTimeThreshold, _config.PasswordCostLowerThreshold); _logger.LogDebug($"Firstrun: Determined {viablePasswordCost} to be the optimal password hashing cost."); _db.Insert(new Configuration { Key = ConfigKeys.PasswordHashingCost, Value = viablePasswordCost.ToString() }); // JWT security Key _logger.LogDebug("Firstrun: Generating JWT security key."); _db.Insert(new Configuration { Key = ConfigKeys.JWTSymmetricSecurityKey, Value = PasswordUtils.GeneratePassword(48, 8) }); // Crypto // 48 characters len with 12 non-alpha-num characters // Ought to be good enough for everyone. -- The IPv4 working group, 1996 var caPassword = PasswordUtils.GeneratePassword(48, 8); var serverPassword = PasswordUtils.GeneratePassword(48, 8); ca = _cryptoService.CreateCertificateAuthorityCertificate($"CN={instanceId}.ca.instance.spectero.io", null, null, caPassword); var serverCertificate = _cryptoService.IssueCertificate($"CN={instanceId}.instance.spectero.io", ca, null, new[] { KeyPurposeID.AnyExtendedKeyUsage, KeyPurposeID.IdKPServerAuth }, serverPassword, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment)); specteroCertKey = PasswordUtils.GeneratePassword(48, 8); specteroCertificate = _cryptoService.IssueCertificate( "CN=" + "spectero", ca, null, new[] { KeyPurposeID.IdKPClientAuth }, specteroCertKey); _db.Insert(new Configuration { Key = ConfigKeys.CeritificationAuthorityPassword, Value = caPassword }); _db.Insert(new Configuration { Key = ConfigKeys.ServerCertificatePassword, Value = serverPassword }); _db.Insert(new Configuration { Key = ConfigKeys.CertificationAuthority, Value = Convert.ToBase64String(_cryptoService.GetCertificateBytes(ca, caPassword)) }); _db.Insert(new Configuration { Key = ConfigKeys.ServerCertificate, Value = Convert.ToBase64String(_cryptoService.GetCertificateBytes(serverCertificate, serverPassword)) }); _db.Insert(new Configuration { Key = ConfigKeys.ServerPFXChain, Value = Convert.ToBase64String(_cryptoService.ExportCertificateChain(serverCertificate, ca)) // Yes, passwordless. Somewhat intentionally, as this is mostly consumed by 3rd party apps. }); // OpenVPN defaults _db.Insert(new Configuration { Key = ConfigKeys.OpenVPNListeners, Value = JsonConvert.SerializeObject(Defaults.OpenVPNListeners) }); _db.Insert(new Configuration { Key = ConfigKeys.OpenVPNBaseConfig, Value = JsonConvert.SerializeObject(Defaults.OpenVPN.Value) }); } if (!_db.TableExists <User>()) { _logger.LogDebug("Firstrun: Creating Users table"); var password = PasswordUtils.GeneratePassword(16, 8); _db.CreateTable <User>(); _db.Insert(new User { AuthKey = "spectero", Roles = new List <User.Role> { User.Role.SuperAdmin }, FullName = "Spectero Administrator", EmailAddress = "*****@*****.**", Password = BCrypt.Net.BCrypt.HashPassword(password, (int)viablePasswordCost), Cert = specteroCertificate != null && ca != null ? Convert.ToBase64String(_cryptoService.ExportCertificateChain(specteroCertificate, ca, specteroCertKey)) : "", CertKey = specteroCertKey, Source = User.SourceTypes.Local, CreatedDate = DateTime.Now }); using (var tw = new StreamWriter(_firstRunConfigName, false)) { tw.WriteLine("username: spectero"); tw.WriteLine($"password: {password}"); } } if (!_db.TableExists <Statistic>()) { _logger.LogDebug("Firstrun: Creating Statistics table"); _db.CreateTable <Statistic>(); _logger.LogInformation("Firstrun: Initialization complete."); } }