Example #1
0
        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);
        }
Example #2
0
        /// <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);
        }
Example #3
0
        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");
        }
Example #4
0
 /// <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);
     }
 }
Example #5
0
 private void FireKeyRemoved(ISshKey key)
 {
     if (KeyRemoved != null)
     {
         SshKeyEventArgs args = new SshKeyEventArgs(key);
         KeyRemoved(this, args);
     }
 }
Example #6
0
 public static Task AddPublicKeyToMetadata(
     InstanceLocator instanceLocator,
     string username,
     ISshKey key)
 => AddPublicKeyToMetadata(
     instanceLocator,
     username,
     Convert.ToBase64String(key.PublicKey));
Example #7
0
        /// <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);
        }
Example #8
0
        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;
        }
Example #10
0
        public void RemoveKey(ISshKey key)
        {
            if (IsLocked)
            {
                throw new AgentLockedException();
            }

            if (mKeyList.Remove(key))
            {
                FireKeyRemoved(key);
            }
        }
Example #11
0
        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;
        }
Example #12
0
        //---------------------------------------------------------------------
        // 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));
        }
Example #13
0
        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");
        }
Example #14
0
 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);
 }
Example #15
0
        /// <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");
        }
Example #16
0
        /// <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);
        }
Example #17
0
        //---------------------------------------------------------------------
        // 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);
                }
            }
        }
Example #18
0
        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);
        }
Example #19
0
        //---------------------------------------------------------------------
        // 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;
        }
Example #21
0
        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);
        }
Example #22
0
        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);
        }
Example #23
0
        /// <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);
        }
Example #24
0
        //---------------------------------------------------------------------
        // 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;
        }
Example #26
0
        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);
            }
        }
Example #27
0
        //---------------------------------------------------------------------
        // 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));
            }
        }
Example #28
0
 public KeyUsedEventArgs(ISshKey key, Process otherProcess)
 {
     Key          = key;
     OtherProcess = otherProcess;
 }
Example #29
0
 /// <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);
 }
Example #30
0
 public KeyNode(ISshKey aKey)
 {
     mKey = aKey;
 }
Example #31
0
        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));
            }
        }
Example #32
0
        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;
        }
Example #33
0
 public KeyUsedEventArgs(ISshKey key, Process otherProcess)
 {
     Key = key;
     OtherProcess = otherProcess;
 }
Example #34
0
 private void FireKeyRemoved(ISshKey key)
 {
     if (KeyRemoved != null) {
     SshKeyEventArgs args = new SshKeyEventArgs(key);
     KeyRemoved(this, args);
       }
 }
Example #35
0
        /// <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);
              }
        }
Example #36
0
 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);
                }
            }
        }
Example #38
0
 /// <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);
 }
Example #39
0
 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);
            }
        }
Example #41
0
        public void RemoveKey(ISshKey key)
        {
            if (IsLocked) {
            throw new AgentLockedException();
              }

              if (mKeyList.Remove(key)) {
            FireKeyRemoved(key);
              }
        }
Example #42
0
 /// <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);
 }
Example #43
0
 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);
       }
 }
Example #44
0
 public SshKeyEventArgs(ISshKey key)
 {
     this.Key = key;
 }
Example #45
0
        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);
        }