public static string GetAuthorizedKeyString(this ISshKey aKey) { string result = ""; switch (aKey.Version) { case SshVersion.SSH1: AsymmetricKeyParameter parameters = aKey.GetPublicKeyParameters(); RsaKeyParameters rsaPublicKeyParameters = (RsaKeyParameters)parameters; result = aKey.Size + " " + rsaPublicKeyParameters.Exponent.ToString(10) + " " + rsaPublicKeyParameters.Modulus.ToString(10) + " " + String.Format(aKey.GetMD5Fingerprint().ToHexString()) + " " + aKey.Comment; break; case SshVersion.SSH2: result = PublicKeyAlgorithmExt.GetIdentifierString(aKey.Algorithm) + " " + Convert.ToBase64String(aKey.GetPublicKeyBlob()) + " " + String.Format(aKey.GetMD5Fingerprint().ToHexString()) + " " + aKey.Comment; break; default: result = "# unsuported SshVersion: '" + aKey.Version + "'"; break; } return(result); }
/// <summary> /// Adds Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM constraint to key /// </summary> public static void addConfirmConstraint(this ISshKey aKey) { var constraint = new Agent.KeyConstraint(); constraint.Type = Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM; aKey.AddConstraint(constraint); }
public static ISigner GetSigner(this ISshKey key) { AsymmetricKeyParameter publicKey = key.GetPublicKeyParameters(); if (publicKey is DsaPublicKeyParameters) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.IdDsaWithSha1)); } else if (publicKey is RsaKeyParameters) { return(SignerUtilities.GetSigner(PkcsObjectIdentifiers.Sha1WithRsaEncryption)); } else if (publicKey is ECPublicKeyParameters) { int ecdsaFieldSize = ((ECPublicKeyParameters)publicKey).Q.Curve.FieldSize; if (ecdsaFieldSize <= 256) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha256)); } else if (ecdsaFieldSize > 256 && ecdsaFieldSize <= 384) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha384)); } else if (ecdsaFieldSize > 384) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha512)); } } else if (publicKey is Ed25519PublicKeyParameter) { return(new Ed25519Signer()); } throw new Exception("Unsupported algorithm"); }
/// <summary> /// Serialize ISshKey to file /// </summary> /// <param name="aKey">the key to serialize</param> /// <param name="aFileName">target file</param> public void SerializeToFile(ISshKey aKey, string aFileName) { using (FileStream stream = new FileStream(aFileName, FileMode.CreateNew, FileAccess.Write)) { Serialize(stream, aKey); } }
private void FireKeyRemoved(ISshKey key) { if (KeyRemoved != null) { SshKeyEventArgs args = new SshKeyEventArgs(key); KeyRemoved(this, args); } }
public static Task AddPublicKeyToMetadata( InstanceLocator instanceLocator, string username, ISshKey key) => AddPublicKeyToMetadata( instanceLocator, username, Convert.ToBase64String(key.PublicKey));
/// <summary> /// Adds Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME constraint to key /// </summary> public static void addLifetimeConstraint(this ISshKey aKey, uint aLifetime) { var constraint = new Agent.KeyConstraint(); constraint.Type = Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME; constraint.Data = aLifetime; aKey.AddConstraint(constraint); }
public byte[] SignRequest(ISshKey aKey, byte[] aSignData) { BlobBuilder builder = new BlobBuilder(); switch (aKey.Version) { case SshVersion.SSH1: builder.AddBytes(aKey.GetPublicKeyBlob()); var engine = new Pkcs1Encoding(new RsaEngine()); engine.Init(true /* encrypt */, aKey.GetPublicKeyParameters()); var encryptedData = engine.ProcessBlock(aSignData, 0, aSignData.Length); var challenge = new BigInteger(encryptedData); builder.AddSsh1BigIntBlob(challenge); builder.AddBytes(SessionId); builder.AddInt(1); // response type - must be 1 builder.InsertHeader(Agent.Message.SSH1_AGENTC_RSA_CHALLENGE); break; case SshVersion.SSH2: builder.AddBlob(aKey.GetPublicKeyBlob()); builder.AddBlob(aSignData); builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST); break; default: throw new Exception(cUnsupportedSshVersion); } BlobParser replyParser = SendMessage(builder); var header = replyParser.ReadHeader(); switch (aKey.Version) { case SshVersion.SSH1: if (header.Message != Agent.Message.SSH1_AGENT_RSA_RESPONSE) { throw new AgentFailureException(); } byte[] response = new byte[16]; for (int i = 0; i < 16; i++) { response[i] = replyParser.ReadUInt8(); } return(response); case SshVersion.SSH2: if (header.Message != Agent.Message.SSH2_AGENT_SIGN_RESPONSE) { throw new AgentFailureException(); } return(replyParser.ReadBlob()); default: throw new Exception(cUnsupportedSshVersion); } }
//--------------------------------------------------------------------- // Ctor. //--------------------------------------------------------------------- protected SshConnectionBase( string username, IPEndPoint endpoint, ISshKey key, ReceiveDataHandler receiveHandler, ReceiveErrorHandler receiveErrorHandler) : base(username, endpoint, key) { this.receiveDataHandler = receiveHandler; this.receiveErrorHandler = receiveErrorHandler; }
public void RemoveKey(ISshKey key) { if (IsLocked) { throw new AgentLockedException(); } if (mKeyList.Remove(key)) { FireKeyRemoved(key); } }
private AuthorizedKey( ISshKey key, AuthorizeKeyMethods method, string posixUsername) { Debug.Assert(IsValidUsername(posixUsername)); Debug.Assert(method.IsSingleFlag()); this.Key = key; this.AuthorizationMethod = method; this.Username = posixUsername; }
//--------------------------------------------------------------------- // Factory methods. //--------------------------------------------------------------------- public static AuthorizedKey ForOsLoginAccount( ISshKey key, PosixAccount posixAccount) { Utilities.ThrowIfNull(key, nameof(key)); Utilities.ThrowIfNull(posixAccount, nameof(posixAccount)); Debug.Assert(IsValidUsername(posixAccount.Username)); return(new AuthorizedKey( key, AuthorizeKeyMethods.Oslogin, posixAccount.Username)); }
public static byte[] FormatSignature(this ISshKey key, byte[] signature) { AsymmetricKeyParameter publicKey = key.GetPublicKeyParameters(); if (publicKey is DsaPublicKeyParameters || publicKey is ECPublicKeyParameters) { Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(signature); BigInteger r = ((DerInteger)seq[0]).PositiveValue; BigInteger s = ((DerInteger)seq[1]).PositiveValue; BlobBuilder formatedSignature = new BlobBuilder(); if (publicKey is ECPublicKeyParameters) { var bytes = r.ToByteArray().ToList(); while (bytes.Count < 20) { bytes.Insert(0, 0); } formatedSignature.AddBlob(bytes.ToArray()); bytes = s.ToByteArray().ToList(); while (bytes.Count < 20) { bytes.Insert(0, 0); } formatedSignature.AddBlob(bytes.ToArray()); } else { var bytes = r.ToByteArrayUnsigned().ToList(); while (bytes.Count < 20) { bytes.Insert(0, 0); } formatedSignature.AddBytes(bytes.ToArray()); bytes = s.ToByteArrayUnsigned().ToList(); while (bytes.Count < 20) { bytes.Insert(0, 0); } formatedSignature.AddBytes(bytes.ToArray()); } return(formatedSignature.GetBlob()); } else if (publicKey is RsaKeyParameters || publicKey is Ed25519PublicKeyParameter) { return(signature); } throw new Exception("Unsupported algorithm"); }
public static bool ConfirmCallback(ISshKey key, Process process) { var programName = Strings.askConfirmKeyUnknownProcess; if (process != null) { programName = string.Format("{0} ({1})", process.MainWindowTitle, process.ProcessName); } var result = MessageBox.Show( string.Format(Strings.askConfirmKey, programName, key.Comment, key.GetMD5Fingerprint().ToHexString()), Util.AssemblyTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2 ); return (result == DialogResult.Yes); }
/// <summary> /// Get a signer for a key. The algorithm is determined by the type of the /// key and in the case of RSA keys, the optional flags. /// </summary> /// <param name="key">A SSH key</param> /// <param name="flags">Optional flags</param> /// <returns>A Signer</returns> public static ISigner GetSigner(this ISshKey key, SignRequestFlags flags = default(SignRequestFlags)) { var publicKey = key.GetPublicKeyParameters(); if (publicKey is DsaPublicKeyParameters) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.IdDsaWithSha1)); } else if (publicKey is RsaKeyParameters) { // flags can influence hash type for RSA keys if (flags.HasFlag(SignRequestFlags.SSH_AGENT_RSA_SHA2_512)) { return(SignerUtilities.GetSigner(PkcsObjectIdentifiers.Sha512WithRsaEncryption)); } if (flags.HasFlag(SignRequestFlags.SSH_AGENT_RSA_SHA2_256)) { return(SignerUtilities.GetSigner(PkcsObjectIdentifiers.Sha256WithRsaEncryption)); } return(SignerUtilities.GetSigner(PkcsObjectIdentifiers.Sha1WithRsaEncryption)); } else if (publicKey is ECPublicKeyParameters) { var ecdsaFieldSize = ((ECPublicKeyParameters)publicKey).Q.Curve.FieldSize; if (ecdsaFieldSize <= 256) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha256)); } else if (ecdsaFieldSize > 256 && ecdsaFieldSize <= 384) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha384)); } else if (ecdsaFieldSize > 384) { return(SignerUtilities.GetSigner(X9ObjectIdentifiers.ECDsaWithSha512)); } } else if (publicKey is Ed25519PublicKeyParameter) { return(new Ed25519Signer()); } throw new ArgumentException("Unsupported algorithm", "key"); }
/// <summary> /// Adds key to SSH agent /// </summary> /// <param name="key">the key to add</param> /// <param name="aConstraints">constraints to apply</param> /// <returns>true if operation was successful</returns> /// <remarks>ignores constraints in key.Constraints</remarks> public void AddKey(ISshKey key, ICollection <Agent.KeyConstraint> aConstraints) { var builder = CreatePrivateKeyBlob(key); if (aConstraints != null && aConstraints.Count > 0) { foreach (var constraint in aConstraints) { builder.AddUInt8((byte)constraint.Type); if (constraint.Type.GetDataType() == typeof(uint)) { builder.AddUInt32((uint)constraint.Data); } } switch (key.Version) { case SshVersion.SSH1: builder.InsertHeader(Agent.Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED); break; case SshVersion.SSH2: builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED); break; default: throw new Exception(cUnsupportedSshVersion); } } else { switch (key.Version) { case SshVersion.SSH1: builder.InsertHeader(Agent.Message.SSH1_AGENTC_ADD_RSA_IDENTITY); break; case SshVersion.SSH2: builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY); break; default: throw new Exception(cUnsupportedSshVersion); } } SendMessageAndCheckSuccess(builder); FireKeyAdded(key); }
//--------------------------------------------------------------------- // IOsLoginAdapter. //--------------------------------------------------------------------- public async Task <LoginProfile> ImportSshPublicKeyAsync( string projectId, ISshKey key, TimeSpan validity, CancellationToken token) { using (ApplicationTraceSources.Default.TraceMethod().WithParameters(projectId)) { var expiryTimeUsec = new DateTimeOffset(DateTime.UtcNow.Add(validity)) .ToUnixTimeMilliseconds() * 1000; var userEmail = this.authorizationAdapter.Authorization.Email; Debug.Assert(userEmail != null); var request = this.service.Users.ImportSshPublicKey( new SshPublicKey() { Key = $"{key.Type} {key.PublicKeyString}", ExpirationTimeUsec = expiryTimeUsec }, $"users/{userEmail}"); request.ProjectId = projectId; try { var response = await request .ExecuteAsync(token) .ConfigureAwait(false); return(response.LoginProfile); } catch (GoogleApiException e) when(e.IsAccessDenied()) { // // Likely reason: The user account is a consumer account or // an administrator has disable POSIX account/SSH key information // updates in the Admin Console. // throw new ResourceAccessDeniedException( "You do not have sufficient permissions to use OS Login: "******"access denied", HelpTopics.ManagingOsLogin, e); } } }
private BlobBuilder CreatePublicKeyBlob(ISshKey aKey) { var builder = new BlobBuilder(); switch (aKey.Version) { case SshVersion.SSH1: builder.AddBytes(aKey.GetPublicKeyBlob()); break; case SshVersion.SSH2: builder.AddBlob(aKey.GetPublicKeyBlob()); break; } return(builder); }
//--------------------------------------------------------------------- // Ctor. //--------------------------------------------------------------------- protected SshWorkerThread( string username, IPEndPoint endpoint, ISshKey key) { this.username = username; this.endpoint = endpoint; this.key = key; this.readyToSend = UnsafeNativeMethods.WSACreateEvent(); this.workerCancellationSource = new CancellationTokenSource(); this.workerThread = new Thread(WorkerThreadProc) { Name = $"SSH worker for {this.username}@{this.endpoint}", IsBackground = true }; }
//--------------------------------------------------------------------- // Ctor. //--------------------------------------------------------------------- protected SshConnectionBase( string username, IPEndPoint endpoint, ISshKey key, ReceiveStringDataHandler receiveHandler, ReceiveErrorHandler receiveErrorHandler, Encoding dataEncoding) : base(username, endpoint, key) { this.receiveDecoder = new StreamingDecoder( dataEncoding, s => receiveHandler(s)); this.receiveDataHandler = (buf, offset, count) => this.receiveDecoder.Decode(buf, (int)offset, (int)count); this.receiveErrorHandler = receiveErrorHandler; }
public static bool ConfirmCallback(ISshKey key, Process process) { var programName = Strings.askConfirmKeyUnknownProcess; if (process != null) { programName = string.Format("{0} ({1})", process.MainWindowTitle, process.ProcessName); } var result = MessageBox.Show( string.Format(Strings.askConfirmKey, programName, key.Comment, key.GetMD5Fingerprint().ToHexString()), Util.AssemblyTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, TopMost | SetForeground | SystemModal ); return(result == DialogResult.Yes); }
public void AddKey(ISshKey key) { if (IsLocked) { throw new AgentLockedException(); } /* handle constraints */ foreach (KeyConstraint constraint in key.Constraints) { if (constraint.Type == KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM && ConfirmUserPermissionCallback == null) { // can't add key with confirm constraint if we don't have // confirm callback throw new CallbackNullException(); } if (constraint.Type == Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME) { UInt32 lifetime = (UInt32)constraint.Data * 1000; Timer timer = new Timer(lifetime); ElapsedEventHandler onTimerElapsed = null; onTimerElapsed = delegate(object aSender, ElapsedEventArgs aEventArgs) { timer.Elapsed -= onTimerElapsed; RemoveKey(key); }; timer.Elapsed += onTimerElapsed; timer.Start(); } } /* first remove matching key if it exists */ ISshKey matchingKey = mKeyList.Get(key.Version, key.GetPublicKeyBlob()); RemoveKey(matchingKey); mKeyList.Add(key); FireKeyAdded(key); }
/// <summary> /// Remove key from SSH agent /// </summary> /// <param name="key">The key to remove</param> /// <returns>true if removal succeeded</returns> public void RemoveKey(ISshKey key) { var builder = CreatePublicKeyBlob(key); switch (key.Version) { case SshVersion.SSH1: builder.InsertHeader(Agent.Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY); break; case SshVersion.SSH2: builder.InsertHeader(Agent.Message.SSH2_AGENTC_REMOVE_IDENTITY); break; default: throw new Exception(cUnsupportedSshVersion); } SendMessageAndCheckSuccess(builder); FireKeyRemoved(key); }
//--------------------------------------------------------------------- // Ctor. //--------------------------------------------------------------------- public SshShellConnection( string username, IPEndPoint endpoint, ISshKey key, string terminal, TerminalSize terminalSize, CultureInfo language, ReceiveStringDataHandler receiveDataHandler, ReceiveErrorHandler receiveErrorHandler) : base( username, endpoint, key, (buf, offset, count) => // TODO: handle partial UTF-8 sequences receiveDataHandler(Encoding.GetString(buf, (int)offset, (int)count)), receiveErrorHandler) { this.terminal = terminal; this.terminalSize = terminalSize; this.language = language; }
//--------------------------------------------------------------------- // Ctor. //--------------------------------------------------------------------- public SshShellConnection( string username, IPEndPoint endpoint, ISshKey key, string terminal, TerminalSize terminalSize, CultureInfo language, ReceiveStringDataHandler receiveDataHandler, ReceiveErrorHandler receiveErrorHandler) : base( username, endpoint, key, receiveDataHandler, receiveErrorHandler, Encoding) { this.terminal = terminal; this.terminalSize = terminalSize; this.language = language; }
public static byte[] GetMD5Fingerprint(this ISshKey key) { try { using (MD5 md5 = MD5.Create()) { if (key.GetPublicKeyParameters() is RsaKeyParameters && key.Version == SshVersion.SSH1) { var rsaKeyParameters = key.GetPublicKeyParameters() as RsaKeyParameters; int modSize = rsaKeyParameters.Modulus.ToByteArrayUnsigned().Length; int expSize = rsaKeyParameters.Exponent.ToByteArrayUnsigned().Length; byte[] md5Buffer = new byte[modSize + expSize]; rsaKeyParameters.Modulus.ToByteArrayUnsigned().CopyTo(md5Buffer, 0); rsaKeyParameters.Exponent.ToByteArrayUnsigned().CopyTo(md5Buffer, modSize); return(md5.ComputeHash(md5Buffer)); } return(md5.ComputeHash(key.GetPublicKeyBlob(false))); } } catch (Exception) { return(null); } }
//--------------------------------------------------------------------- // IOsLoginService. //--------------------------------------------------------------------- public async Task <AuthorizedKey> AuthorizeKeyAsync( string projectId, OsLoginSystemType os, ISshKey key, TimeSpan validity, CancellationToken token) { Utilities.ThrowIfNullOrEmpty(projectId, nameof(projectId)); Utilities.ThrowIfNull(key, nameof(key)); if (os != OsLoginSystemType.Linux) { throw new ArgumentException(nameof(os)); } if (validity.TotalSeconds <= 0) { throw new ArgumentException(nameof(validity)); } using (ApplicationTraceSources.Default.TraceMethod().WithParameters(projectId)) { // // If OS Login is enabled for a project, we have to use // the Posix username from the OS Login login profile. // // Note that the Posix account managed by OS login can // differ based on the project that we're trying to access. // Therefore, make sure to specify the project when // importing the key. // // OS Login auto-generates a username for us. Again, this // username might differ based on project/organization. // // // Import the key for the given project. // var loginProfile = await this.adapter.ImportSshPublicKeyAsync( projectId, key, validity, token) .ConfigureAwait(false); // // Although rare, there could be multiple POSIX accounts. // var account = loginProfile.PosixAccounts .EnsureNotNull() .FirstOrDefault(a => a.Primary == true && a.OperatingSystemType == "LINUX"); if (account == null) { // // This is strange, the account should have been created. // throw new OsLoginSshKeyImportFailedException( "Imported SSH key to OSLogin, but no POSIX account was created", HelpTopics.TroubleshootingOsLogin); } return(AuthorizedKey.ForOsLoginAccount(key, account)); } }
public KeyUsedEventArgs(ISshKey key, Process otherProcess) { Key = key; OtherProcess = otherProcess; }
/// <summary> /// Adds key to SSH agent /// </summary> /// <param name="key">the key to add</param> /// <returns>true if operation was successful</returns> /// <remarks>applies constraints in aKeys.Constraints, if any</remarks> public void AddKey(ISshKey key) { AddKey(key, key.Constraints); }
public KeyNode(ISshKey aKey) { mKey = aKey; }
public static AuthorizedKey ForMetadata( ISshKey key, string preferredUsername, bool useInstanceKeySet, IAuthorization authorization) { Utilities.ThrowIfNull(key, nameof(key)); if (preferredUsername != null) { if (!IsValidUsername(preferredUsername)) { throw new ArgumentException( $"The username '{preferredUsername}' is not a valid username"); } else { // // Use the preferred username. // return(new AuthorizedKey( key, useInstanceKeySet ? AuthorizeKeyMethods.InstanceMetadata : AuthorizeKeyMethods.ProjectMetadata, preferredUsername)); } } else { Utilities.ThrowIfNull(authorization, nameof(authorization)); // // No preferred username provided, so derive one // from the user's email address: // // 1. Remove all characters following and including '@'. // 2. Lowercase all alpha characters. // 3. Replace all non-alphanum characters with '_'. // var username = new string(authorization.Email .Split('@')[0] .ToLower() .Select(c => IsAsciiLetterOrNumber(c) ? c : '_') .ToArray()); // // 4. Prepend with 'g' if the username does not start with an alpha character. // if (!IsAsciiLetter(username[0])) { username = "******" + username; } // // 5. Truncate the username to 32 characters. // username = username.Substring(0, Math.Min(MaxUsernameLength, username.Length)); return(new AuthorizedKey( key, useInstanceKeySet ? AuthorizeKeyMethods.InstanceMetadata : AuthorizeKeyMethods.ProjectMetadata, username)); } }
private BlobBuilder CreatePublicKeyBlob(ISshKey aKey) { var builder = new BlobBuilder(); switch (aKey.Version) { case SshVersion.SSH1: builder.AddBytes(aKey.GetPublicKeyBlob()); break; case SshVersion.SSH2: builder.AddBlob(aKey.GetPublicKeyBlob()); break; } return builder; }
BlobBuilder CreatePrivateKeyBlob(ISshKey key) { var builder = new BlobBuilder(); switch (key.Version) { case SshVersion.SSH1: var privateKeyParams = key.GetPrivateKeyParameters() as RsaPrivateCrtKeyParameters; builder.AddInt(key.Size); builder.AddSsh1BigIntBlob(privateKeyParams.Modulus); builder.AddSsh1BigIntBlob(privateKeyParams.PublicExponent); builder.AddSsh1BigIntBlob(privateKeyParams.Exponent); builder.AddSsh1BigIntBlob(privateKeyParams.QInv); builder.AddSsh1BigIntBlob(privateKeyParams.Q); builder.AddSsh1BigIntBlob(privateKeyParams.P); break; case SshVersion.SSH2: builder.AddStringBlob(key.Algorithm.GetIdentifierString()); switch (key.Algorithm) { case PublicKeyAlgorithm.SSH_DSS: var dsaPublicKeyParameters = key.GetPublicKeyParameters() as DsaPublicKeyParameters; var dsaPrivateKeyParamters = key.GetPrivateKeyParameters() as DsaPrivateKeyParameters; builder.AddBigIntBlob(dsaPublicKeyParameters.Parameters.P); builder.AddBigIntBlob(dsaPublicKeyParameters.Parameters.Q); builder.AddBigIntBlob(dsaPublicKeyParameters.Parameters.G); builder.AddBigIntBlob(dsaPublicKeyParameters.Y); builder.AddBigIntBlob(dsaPrivateKeyParamters.X); break; case PublicKeyAlgorithm.ECDSA_SHA2_NISTP256: case PublicKeyAlgorithm.ECDSA_SHA2_NISTP384: case PublicKeyAlgorithm.ECDSA_SHA2_NISTP521: var ecdsaPublicKeyParameters = key.GetPublicKeyParameters() as ECPublicKeyParameters; var ecdsaPrivateKeyParameters = key.GetPrivateKeyParameters() as ECPrivateKeyParameters; builder.AddStringBlob(key.Algorithm.GetIdentifierString() .Replace(PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_PREFIX, string.Empty)); builder.AddBlob(ecdsaPublicKeyParameters.Q.GetEncoded()); builder.AddBigIntBlob(ecdsaPrivateKeyParameters.D); break; case PublicKeyAlgorithm.SSH_RSA: var rsaPrivateKeyParameters = key.GetPrivateKeyParameters() as RsaPrivateCrtKeyParameters; builder.AddBigIntBlob(rsaPrivateKeyParameters.Modulus); builder.AddBigIntBlob(rsaPrivateKeyParameters.PublicExponent); builder.AddBigIntBlob(rsaPrivateKeyParameters.Exponent); builder.AddBigIntBlob(rsaPrivateKeyParameters.QInv); builder.AddBigIntBlob(rsaPrivateKeyParameters.P); builder.AddBigIntBlob(rsaPrivateKeyParameters.Q); break; case PublicKeyAlgorithm.ED25519: var ed25519PublicKeyParameters = key.GetPublicKeyParameters() as Ed25519PublicKeyParameter; var ed25519PrivateKeyParameters = key.GetPrivateKeyParameters() as Ed25519PrivateKeyParameter; builder.AddBlob(ed25519PublicKeyParameters.Key); builder.AddBlob(ed25519PrivateKeyParameters.Signature); break; default: throw new Exception("Unsupported algorithm"); } break; default: throw new Exception(cUnsupportedSshVersion); } builder.AddStringBlob(key.Comment); return builder; }
//--------------------------------------------------------------------- // IPublicKeyService. //--------------------------------------------------------------------- public async Task <AuthorizedKey> AuthorizeKeyAsync( InstanceLocator instance, ISshKey key, TimeSpan validity, string preferredPosixUsername, AuthorizeKeyMethods allowedMethods, CancellationToken token) { Utilities.ThrowIfNull(instance, nameof(key)); Utilities.ThrowIfNull(key, nameof(key)); using (ApplicationTraceSources.Default.TraceMethod().WithParameters(instance)) { // // Query metadata for instance and project in parallel. // var instanceDetailsTask = this.computeEngineAdapter.GetInstanceAsync( instance, token) .ConfigureAwait(false); var projectDetailsTask = this.computeEngineAdapter.GetProjectAsync( instance.ProjectId, token) .ConfigureAwait(false); var instanceDetails = await instanceDetailsTask; var projectDetails = await projectDetailsTask; var osLoginEnabled = IsFlagEnabled( projectDetails, instanceDetails, EnableOsLoginFlag); ApplicationTraceSources.Default.TraceVerbose( "OS Login status for {0}: {1}", instance, osLoginEnabled); if (osLoginEnabled) { // // If OS Login is enabled, it has to be used. Any metadata keys // are ignored. // if (!allowedMethods.HasFlag(AuthorizeKeyMethods.Oslogin)) { throw new InvalidOperationException( $"{instance} requires OS Login to beused"); } if (IsFlagEnabled(projectDetails, instanceDetails, EnableOsLoginMultiFactorFlag)) { throw new NotImplementedException( "OS Login 2-factor authentication is not supported"); } // // NB. It's cheaper to unconditionally push the key than // to check for previous keys first. // return(await this.osLoginService.AuthorizeKeyAsync( instance.ProjectId, OsLoginSystemType.Linux, key, validity, token) .ConfigureAwait(false)); } else { var instanceMetadata = instanceDetails.Metadata; var projectMetadata = projectDetails.CommonInstanceMetadata; // // Check if there is a legacy SSH key. If there is one, // other keys are ignored. // // NB. legacy SSH keys were instance-only, so checking // the instance metadata is sufficient. // if (IsLegacySshKeyPresent(instanceMetadata)) { throw new UnsupportedLegacySshKeyEncounteredException( $"Connecting to the VM instance {instance.Name} is not supported " + "because the instance uses legacy SSH keys in its metadata (sshKeys)", HelpTopics.ManagingMetadataAuthorizedKeys); } // // There is no legacy key, so we're good to push a new key. // // Now figure out which username to use and where to push it. // var blockProjectSshKeys = IsFlagEnabled( projectDetails, instanceDetails, BlockProjectSshKeysFlag); bool useInstanceKeySet; if (allowedMethods.HasFlag(AuthorizeKeyMethods.ProjectMetadata) && allowedMethods.HasFlag(AuthorizeKeyMethods.InstanceMetadata)) { // // Both allowed - use project metadata unless: // - project keys are blocked // - we do not have the permission to update project metadata. // var canUpdateProjectMetadata = await this.resourceManagerAdapter .IsGrantedPermission( instance.ProjectId, Permissions.ComputeProjectsSetCommonInstanceMetadata, token) .ConfigureAwait(false); useInstanceKeySet = blockProjectSshKeys || !canUpdateProjectMetadata; } else if (allowedMethods.HasFlag(AuthorizeKeyMethods.ProjectMetadata)) { // Only project allowed. if (blockProjectSshKeys) { throw new InvalidOperationException( $"Project {instance.ProjectId} does not allow project-level SSH keys"); } else { useInstanceKeySet = false; } } else if (allowedMethods.HasFlag(AuthorizeKeyMethods.InstanceMetadata)) { // Only instance allowed. useInstanceKeySet = true; } else { // Neither project nor instance allowed. throw new ArgumentException(nameof(allowedMethods)); } var profile = AuthorizedKey.ForMetadata( key, preferredPosixUsername, useInstanceKeySet, this.authorizationAdapter.Authorization); Debug.Assert(profile.Username != null); var metadataKey = new ManagedMetadataAuthorizedKey( profile.Username, key.Type, key.PublicKeyString, new ManagedKeyMetadata( this.authorizationAdapter.Authorization.Email, DateTime.UtcNow.Add(validity))); var existingKeySet = MetadataAuthorizedKeySet.FromMetadata( useInstanceKeySet ? instanceMetadata : projectMetadata); if (existingKeySet .RemoveExpiredKeys() .Contains(metadataKey)) { // // The key is there already, so we are all set. // ApplicationTraceSources.Default.TraceVerbose( "Existing SSH key found for {0}", profile.Username); } else { // // Key not known yet, so we have to push it to // the metadata. // ApplicationTraceSources.Default.TraceVerbose( "Pushing new SSH key for {0}", profile.Username); await PushPublicKeyToMetadataAsync( instance, useInstanceKeySet, metadataKey, token) .ConfigureAwait(false); } return(profile); } } }
public KeyWrapper(ISshKey key) { this.key = key; }
public override void Serialize(Stream stream, object obj) { /* check for required parameters */ if (stream == null) { throw new ArgumentNullException("stream"); } if (obj == null) { throw new ArgumentNullException("obj"); } PinnedArray <char> passphrase = null; string ciphername; if (passphrase == null || passphrase.Data.Length == 0) { ciphername = KDFNAME_NONE; } else { ciphername = KDFNAME_BCRYPT; } var builder = new BlobBuilder(); ISshKey sshKey = obj as ISshKey; if (sshKey == null) { throw new ArgumentException("Expected ISshKey", "obj"); } var publicKeyParams = sshKey.GetPublicKeyParameters() as Ed25519PublicKeyParameter; var privateKeyParams = sshKey.GetPrivateKeyParameters() as Ed25519PrivateKeyParameter; /* writing info headers */ builder.AddBytes(Encoding.ASCII.GetBytes(AUTH_MAGIC)); builder.AddStringBlob(ciphername); builder.AddStringBlob(ciphername); //kdfname builder.AddBlob(new byte[0]); // kdfoptions /* writing public key */ builder.AddInt(1); // number of keys N var publicKeyBuilder = new BlobBuilder(); publicKeyBuilder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString()); publicKeyBuilder.AddBlob(publicKeyParams.Key); builder.AddBlob(publicKeyBuilder.GetBlob()); /* writing private key */ BlobBuilder privateKeyBuilder = new BlobBuilder(); var checkint = new SecureRandom().NextInt(); privateKeyBuilder.AddInt(checkint); privateKeyBuilder.AddInt(checkint); privateKeyBuilder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString()); privateKeyBuilder.AddBlob(publicKeyParams.Key); privateKeyBuilder.AddBlob(privateKeyParams.Signature); privateKeyBuilder.AddStringBlob(sshKey.Comment); if (ciphername == KDFNAME_NONE) { /* plain-text */ builder.AddBlob(privateKeyBuilder.GetBlobAsPinnedByteArray().Data); } else { byte[] keydata; using (MD5 md5 = MD5.Create()) { keydata = md5.ComputeHash(Encoding.ASCII.GetBytes(passphrase.Data)); } passphrase.Dispose(); } /* writing result to file */ var builderOutput = builder.GetBlobAsPinnedByteArray(); using (var writer = new StreamWriter(stream)) { writer.NewLine = "\n"; writer.WriteLine(MARK_BEGIN); var base64Data = Util.ToBase64(builderOutput.Data); var base64String = Encoding.UTF8.GetString(base64Data); var offset = 0; while (offset < base64String.Length) { const int maxLineLength = 70; if (offset + maxLineLength > base64String.Length) { writer.WriteLine(base64String.Substring(offset)); } else { writer.WriteLine(base64String.Substring(offset, maxLineLength)); } offset += maxLineLength; } writer.WriteLine(MARK_END); } }
/// <summary> /// Adds key to SSH agent /// </summary> /// <param name="key">the key to add</param> /// <param name="aConstraints">constraints to apply</param> /// <returns>true if operation was successful</returns> /// <remarks>ignores constraints in key.Constraints</remarks> public void AddKey(ISshKey key, ICollection<Agent.KeyConstraint> aConstraints) { var builder = CreatePrivateKeyBlob(key); if (aConstraints != null && aConstraints.Count > 0) { foreach (var constraint in aConstraints) { builder.AddByte((byte)constraint.Type); if (constraint.Type.GetDataType() == typeof(uint)) { builder.AddInt((uint)constraint.Data); } } switch (key.Version) { case SshVersion.SSH1: builder.InsertHeader(Agent.Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED); break; case SshVersion.SSH2: builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED); break; default: throw new Exception(cUnsupportedSshVersion); } } else { switch (key.Version) { case SshVersion.SSH1: builder.InsertHeader(Agent.Message.SSH1_AGENTC_ADD_RSA_IDENTITY); break; case SshVersion.SSH2: builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY); break; default: throw new Exception(cUnsupportedSshVersion); } } SendMessageAndCheckSuccess(builder); FireKeyAdded(key); }
public byte[] SignRequest(ISshKey aKey, byte[] aSignData) { BlobBuilder builder = new BlobBuilder(); switch (aKey.Version) { case SshVersion.SSH1: builder.AddBytes(aKey.GetPublicKeyBlob()); var engine = new Pkcs1Encoding(new RsaEngine()); engine.Init(true /* encrypt */, aKey.GetPublicKeyParameters()); var encryptedData = engine.ProcessBlock(aSignData, 0, aSignData.Length); var challenge = new BigInteger(encryptedData); builder.AddSsh1BigIntBlob(challenge); builder.AddBytes(SessionId); builder.AddInt(1); // response type - must be 1 builder.InsertHeader(Agent.Message.SSH1_AGENTC_RSA_CHALLENGE); break; case SshVersion.SSH2: builder.AddBlob(aKey.GetPublicKeyBlob()); builder.AddBlob(aSignData); builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST); break; default: throw new Exception(cUnsupportedSshVersion); } BlobParser replyParser = SendMessage(builder); var header = replyParser.ReadHeader(); switch (aKey.Version) { case SshVersion.SSH1: if (header.Message != Agent.Message.SSH1_AGENT_RSA_RESPONSE) { throw new AgentFailureException(); } byte[] response = new byte[16]; for (int i = 0; i < 16; i++) { response[i] = replyParser.ReadByte(); } return response; case SshVersion.SSH2: if (header.Message != Agent.Message.SSH2_AGENT_SIGN_RESPONSE) { throw new AgentFailureException(); } return replyParser.ReadBlob(); default: throw new Exception(cUnsupportedSshVersion); } }
public SshKeyEventArgs(ISshKey key) { this.Key = key; }