AddStringBlob() публичный метод

Adds a string to the blob
public AddStringBlob ( string aString ) : void
aString string the string to add
Результат void
Пример #1
0
        OpensshCertificate ReadCertificate(BlobBuilder builder)
        {
            var serial = ReadUInt64();

            builder.AddUInt64(serial);
            var type = (Ssh2CertType)ReadUInt32();

            builder.AddUInt32((uint)type);
            var keyId = ReadString();

            builder.AddStringBlob(keyId);
            var validPrincipals = ReadBlob();

            builder.AddBlob(validPrincipals);
            var validAfter = ReadUInt64();

            builder.AddUInt64(validAfter);
            var validBefore = ReadUInt64();

            builder.AddUInt64(validBefore);
            var criticalOptions = ReadBlob();

            builder.AddBlob(criticalOptions);
            var extensions = ReadBlob();

            builder.AddBlob(extensions);
            var reserved = ReadBlob();

            builder.AddBlob(reserved);
            var signatureKey = ReadBlob();

            builder.AddBlob(signatureKey);
            var signature = ReadBlob();

            builder.AddBlob(signature);

            var principalsParser = new BlobParser(validPrincipals);
            var principalsList   = new List <string>();

            while (principalsParser.Stream.Position < principalsParser.Stream.Length)
            {
                principalsList.Add(principalsParser.ReadString());
            }
            var validAfterDateTime  = validAfter == ulong.MaxValue ? DateTime.MaxValue : epoch.AddSeconds(validAfter);
            var validBeforeDateTime = validBefore == ulong.MaxValue ? DateTime.MaxValue : epoch.AddSeconds(validBefore);
            var signatureKeyParser  = new BlobParser(signatureKey);
            OpensshCertificate unused;
            var sigKey = signatureKeyParser.ReadSsh2PublicKeyData(out unused);

            return(new OpensshCertificate(builder.GetBlob(), type, serial, keyId,
                                          principalsList, validAfterDateTime,
                                          validBeforeDateTime, criticalOptions,
                                          extensions, sigKey));
        }
Пример #2
0
        public void SendMessageTest()
        {
            // TODO: Need to modify this test so that it does not use PageantAgent
            const string messageValue = "junk";

            var builder = new BlobBuilder ();
            builder.AddStringBlob(messageValue);
            var messageBytes = builder.GetBlob();

            using (var agent = new PageantAgent()) {
                var client = new PageantClient();
                var reply = client.SendMessage(messageBytes);
                var replyParser = new BlobParser(reply);
                var replyHeader = replyParser.ReadHeader();
                Assert.That(replyHeader.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE));
            }
        }
Пример #3
0
        /// <summary>
        /// Answers the message.
        /// </summary>
        /// <param name='messageStream'>Message stream.</param>
        /// <param name="process">The calling process or <c>null</c> if the process
        /// could not be obtained.</param>
        /// <remarks>code based on winpgnt.c from PuTTY source code</remarks>
        public void AnswerMessage(Stream messageStream, Process process = null)
        {
            if (messageStream.CanTimeout) {
            messageStream.ReadTimeout = 5000;
              }
              var messageParser = new BlobParser(messageStream);
              var responseBuilder = new BlobBuilder();
              BlobHeader header;
              try {
            header = messageParser.ReadHeader();

            if (MessageReceived != null) {
              var eventArgs = new MessageReceivedEventArgs(header);
              MessageReceived(this, eventArgs);
              if (eventArgs.Fail) {
            throw new Exception ();
              }
            }
              } catch (Exception) {
            header = new BlobHeader();
            header.Message = Message.UNKNOWN;
            // this will cause the switch statement below to use the default case
            // which returns an error to the stream.
              }

              switch (header.Message) {
            case Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
              /*
               * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
               */
              try {
            if (header.BlobLength > 1) {
              // ruby net-ssh tries to send a SSH2_AGENT_REQUEST_VERSION message
              // which has the same id number as SSH1_AGENTC_REQUEST_RSA_IDENTITIES
              // with a string tacked on. We need to read the string from the
              // stream, but it is not used for anything.
              messageParser.ReadString ();
            }
            var keyList = ListKeys(SshVersion.SSH1);
            if (FilterKeyListCallback != null) {
              keyList = FilterKeyListCallback(keyList);
            }
            foreach (SshKey key in keyList) {
              responseBuilder.AddBytes(key.GetPublicKeyBlob());
              responseBuilder.AddStringBlob(key.Comment);
            }
            responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER,
              keyList.Count);
            // TODO may want to check that there is enough room in the message stream
            break; // succeeded
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH2_AGENTC_REQUEST_IDENTITIES:
              /*
               * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
               */
              try {
            var keyList = ListKeys(SshVersion.SSH2);
            if (FilterKeyListCallback != null) {
              keyList = FilterKeyListCallback(keyList);
            }
            foreach (SshKey key in keyList) {
              responseBuilder.AddBlob(key.GetPublicKeyBlob());
              responseBuilder.AddStringBlob(key.Comment);
            }
            responseBuilder.InsertHeader(Message.SSH2_AGENT_IDENTITIES_ANSWER,
              keyList.Count);
            // TODO may want to check that there is enough room in the message stream
            break; // succeeded
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH1_AGENTC_RSA_CHALLENGE:
              /*
               * Reply with either SSH1_AGENT_RSA_RESPONSE or
               * SSH_AGENT_FAILURE, depending on whether we have that key
               * or not.
               */

              try {
            //Reading publicKey information
            var publicKeyParams = messageParser.ReadSsh1PublicKeyData(true);

            //Searching for Key here
            var matchingKey = mKeyList.Where(key => key.Version == SshVersion.SSH1
                && (key.GetPublicKeyParameters().Equals(publicKeyParams))).Single();

            //Reading challenge
            var encryptedChallenge = messageParser.ReadSsh1BigIntBlob();
            var sessionId = messageParser.ReadBytes(16);

            //Checking responseType field
            if (messageParser.ReadInt() != 1) {
              goto default; //responseType !=1  is not longer supported
            }

            //Answering to the challenge
            var engine = new Pkcs1Encoding(new RsaEngine());
            engine.Init(false /* decrypt */, matchingKey.GetPrivateKeyParameters());

            var decryptedChallenge = engine.ProcessBlock(encryptedChallenge,
                0, encryptedChallenge.Length);

            using (MD5 md5 = MD5.Create()) {
              var md5Buffer = new byte[48];
              decryptedChallenge.CopyTo(md5Buffer, 0);
              sessionId.CopyTo(md5Buffer, 32);

              responseBuilder.AddBytes(md5.ComputeHash(md5Buffer));
              responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_RESPONSE);
              break;
            }
              } catch (InvalidOperationException) {
            // this is expected if there is not a matching key
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }

              goto default; // failed

            case Message.SSH2_AGENTC_SIGN_REQUEST:
              /*
               * Reply with either SSH2_AGENT_SIGN_RESPONSE or SSH_AGENT_FAILURE,
               * depending on whether we have that key or not.
               */
              try {
            var keyBlob = messageParser.ReadBlob();
            var reqData = messageParser.ReadBlob();
            var flags = new SignRequestFlags();
            try {
              // usually, there are no flags, so parser will throw
              flags = (SignRequestFlags)messageParser.ReadInt();
            } catch { }

            var matchingKey =
              mKeyList.Where(key => key.Version == SshVersion.SSH2 &&
              key.GetPublicKeyBlob().SequenceEqual(keyBlob)).First();
            var confirmConstraints = matchingKey.Constraints
              .Where(constraint => constraint.Type ==
                KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
            if (confirmConstraints.Count() > 0) {
              if (!ConfirmUserPermissionCallback.Invoke(matchingKey, process)) {
                goto default;
              }
            }

            /* create signature */
            var signKey = matchingKey;
            var signer = signKey.GetSigner();
            var algName = signKey.Algorithm.GetIdentifierString();
            signer.Init(true, signKey.GetPrivateKeyParameters());
            signer.BlockUpdate(reqData, 0, reqData.Length);
            byte[] signature = signer.GenerateSignature();
            signature = signKey.FormatSignature(signature);
            BlobBuilder signatureBuilder = new BlobBuilder();
            if (!flags.HasFlag(SignRequestFlags.SSH_AGENT_OLD_SIGNATURE)) {
              signatureBuilder.AddStringBlob(algName);
            }
            signatureBuilder.AddBlob(signature);
            responseBuilder.AddBlob(signatureBuilder.GetBlob());
            responseBuilder.InsertHeader(Message.SSH2_AGENT_SIGN_RESPONSE);
            try {
              KeyUsed(this, new KeyUsedEventArgs(signKey, process));
            } catch { }
            break; // succeeded
              } catch (InvalidOperationException) {
            // this is expected if there is not a matching key
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failure

            case Message.SSH1_AGENTC_ADD_RSA_IDENTITY:
            case Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED:
              /*
               * Add to the list and return SSH_AGENT_SUCCESS, or
               * SSH_AGENT_FAILURE if the key was malformed.
               */

              if (IsLocked) {
            goto default;
              }

              bool ssh1constrained = (header.Message == Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED);

              try {
            var publicKeyParams = messageParser.ReadSsh1PublicKeyData(false);
            var keyPair = messageParser.ReadSsh1KeyData(publicKeyParams);

            SshKey key = new SshKey(SshVersion.SSH1, keyPair);
            key.Comment = messageParser.ReadString();
            key.Source = "External client";

            if (ssh1constrained) {
              while (messageStream.Position < header.BlobLength + 4) {
                KeyConstraint constraint = new KeyConstraint();
                constraint.Type = (KeyConstraintType)messageParser.ReadByte();
                if (constraint.Type ==
                  KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME) {
                  constraint.Data = messageParser.ReadInt();
                }
                key.AddConstraint(constraint);
              }
            }
            AddKey(key);
            responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
            break;

              } catch (CallbackNullException) {
            // this is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }

              goto default; // failed

            case Message.SSH2_AGENTC_ADD_IDENTITY:
            case Message.SSH2_AGENTC_ADD_ID_CONSTRAINED:
              /*
               * Add to the list and return SSH_AGENT_SUCCESS, or
               * SSH_AGENT_FAILURE if the key was malformed.
               */

              if (IsLocked) {
            goto default;
              }

              bool constrained = (header.Message ==
              Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);

              try {
            var publicKeyParams = messageParser.ReadSsh2PublicKeyData();
            var keyPair = messageParser.ReadSsh2KeyData(publicKeyParams);
            SshKey key = new SshKey(SshVersion.SSH2, keyPair);
            key.Comment = messageParser.ReadString();
            key.Source = "External client";

            if (constrained) {
              while (messageStream.Position < header.BlobLength + 4) {
                KeyConstraint constraint = new KeyConstraint();
                constraint.Type =
                  (KeyConstraintType)messageParser.ReadByte();
                if (constraint.Type ==
                  KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME) {
                  constraint.Data = messageParser.ReadInt();
                }
                key.AddConstraint(constraint);
              }
            }
            AddKey(key);
            responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
            break; // success!
              } catch (CallbackNullException) {
            // this is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY:
            case Message.SSH2_AGENTC_REMOVE_IDENTITY:
              /*
               * Remove from the list and return SSH_AGENT_SUCCESS, or
               * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
               * start with.
               */

              if (IsLocked) {
            goto default;
              }

              SshVersion removeVersion;
              byte[] rKeyBlob;
              if (header.Message == Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY) {
            removeVersion = SshVersion.SSH1;
            rKeyBlob = messageParser.ReadBytes(header.BlobLength - 1);
              } else if (header.Message == Message.SSH2_AGENTC_REMOVE_IDENTITY) {
            removeVersion = SshVersion.SSH2;
            rKeyBlob = messageParser.ReadBlob();
              } else {
            Debug.Fail("Should not get here.");
            goto default;
              }

              try {
            var matchingKey = mKeyList.Get(removeVersion, rKeyBlob);
            var startKeyListLength = mKeyList.Count;
            RemoveKey(matchingKey);
            // only succeed if key was removed
            if (mKeyList.Count == startKeyListLength - 1) {
              responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
              break; //success!
            }
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
            case Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
              /*
               * Remove all SSH-1 or SSH-2 keys.
               */

              if (IsLocked) {
            goto default;
              }

              SshVersion removeAllVersion;
              if (header.Message == Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES) {
            removeAllVersion = SshVersion.SSH1;
              } else if (header.Message == Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES) {
            removeAllVersion = SshVersion.SSH2;
              } else {
            Debug.Fail("Should not get here.");
            goto default;
              }

              try {
            RemoveAllKeys(removeAllVersion);
            responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
            break; //success!
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH_AGENTC_LOCK:
              try {
            var passphrase = new PinnedArray<byte>(messageParser.ReadBlob());
            try {
              Lock(passphrase.Data);
            } finally {
              passphrase.Clear();
            }
            if (IsLocked) {
              responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
              break;
            }
              } catch (AgentLockedException) {
            // This is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default;

            case Message.SSH_AGENTC_UNLOCK:
              try {
            var passphrase = new PinnedArray<byte>(messageParser.ReadBlob());
            try {
              Unlock(passphrase.Data);
            } finally {
              passphrase.Clear();
            }
            if (!IsLocked) {
              responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
              break;
            }
              } catch (AgentLockedException) {
            // This is expected
              } catch (PassphraseException) {
            // This is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default;

            default:
              responseBuilder.Clear();
              responseBuilder.InsertHeader(Message.SSH_AGENT_FAILURE);
              break;
              }
              /* write response to stream */
              if (messageStream.CanSeek)
            messageStream.Position = 0;
              messageStream.Write(responseBuilder.GetBlob(), 0, responseBuilder.Length);
              messageStream.Flush();
        }
Пример #4
0
        /// <summary>
        /// Gets OpenSsh formatted bytes from public key
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="cert">When set to <c>true</c> and the key has a certificate, the certificate blob will be used.</param>
        /// <returns>byte array containing key information</returns>
        public static byte[] GetPublicKeyBlob(this ISshKey key, bool cert = true)
        {
            if (cert && key.Certificate != null)
            {
                return(key.Certificate.Blob);
            }
            AsymmetricKeyParameter parameters = key.GetPublicKeyParameters();
            BlobBuilder            builder    = new BlobBuilder();

            if (parameters is RsaKeyParameters)
            {
                RsaKeyParameters rsaPublicKeyParameters = (RsaKeyParameters)parameters;
                if (key.Version == SshVersion.SSH1)
                {
                    builder.AddInt(key.Size);
                    builder.AddSsh1BigIntBlob(rsaPublicKeyParameters.Exponent);
                    builder.AddSsh1BigIntBlob(rsaPublicKeyParameters.Modulus);
                }
                else
                {
                    builder.AddStringBlob(PublicKeyAlgorithm.SSH_RSA.GetIdentifierString());
                    builder.AddBigIntBlob(rsaPublicKeyParameters.Exponent);
                    builder.AddBigIntBlob(rsaPublicKeyParameters.Modulus);
                }
            }
            else if (parameters is DsaPublicKeyParameters)
            {
                DsaPublicKeyParameters dsaParameters =
                    (DsaPublicKeyParameters)parameters;

                builder.AddStringBlob(PublicKeyAlgorithm.SSH_DSS.GetIdentifierString());
                builder.AddBigIntBlob(dsaParameters.Parameters.P);
                builder.AddBigIntBlob(dsaParameters.Parameters.Q);
                builder.AddBigIntBlob(dsaParameters.Parameters.G);
                builder.AddBigIntBlob(dsaParameters.Y);
            }
            else if (parameters is ECPublicKeyParameters)
            {
                ECPublicKeyParameters ecdsaParameters =
                    (ECPublicKeyParameters)parameters;

                string algorithm;
                switch (ecdsaParameters.Parameters.Curve.FieldSize)
                {
                case 256:
                    algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP256.GetIdentifierString();
                    break;

                case 384:
                    algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP384.GetIdentifierString();
                    break;

                case 521:
                    algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP521.GetIdentifierString();
                    break;

                default:
                    throw new ArgumentException("Unsupported EC size: " +
                                                ecdsaParameters.Parameters.Curve.FieldSize);
                }
                builder.AddStringBlob(algorithm);
                algorithm =
                    algorithm.Replace(PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_PREFIX,
                                      string.Empty);
                builder.AddStringBlob(algorithm);
                builder.AddBlob(ecdsaParameters.Q.GetEncoded());
            }
            else if (parameters is Ed25519PublicKeyParameter)
            {
                builder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString());
                builder.AddBlob(((Ed25519PublicKeyParameter)parameters).Key);
            }
            else
            {
                throw new ArgumentException(parameters.GetType() + " is not supported");
            }
            byte[] result = builder.GetBlob();
            builder.Clear();
            return(result);
        }
Пример #5
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);
        }
Пример #6
0
        /// <summary>
        /// Gets OpenSsh formatted bytes from public key
        /// </summary>
        /// <param name="Algorithm">AsymmetricAlgorithm to convert.</param>
        /// <returns>byte array containing key information</returns>
        /// <exception cref="ArgumentException">
        /// AsymmetricAlgorithm is not supported
        /// </exception>
        /// <remarks>
        /// Currently only supports RSA and DSA public keys
        /// </remarks>
        public static byte[] GetPublicKeyBlob(this ISshKey aKey)
        {
            AsymmetricKeyParameter parameters = aKey.GetPublicKeyParameters();
              BlobBuilder builder = new BlobBuilder();
              if (parameters is RsaKeyParameters) {
            RsaKeyParameters rsaPublicKeyParameters = (RsaKeyParameters)parameters;
            if (aKey.Version == SshVersion.SSH1) {
              builder.AddInt(aKey.Size);
              builder.AddSsh1BigIntBlob(rsaPublicKeyParameters.Exponent);
              builder.AddSsh1BigIntBlob(rsaPublicKeyParameters.Modulus);
            } else {
              builder.AddStringBlob(PublicKeyAlgorithm.SSH_RSA.GetIdentifierString());
              builder.AddBigIntBlob(rsaPublicKeyParameters.Exponent);
              builder.AddBigIntBlob(rsaPublicKeyParameters.Modulus);
            }
              } else if (parameters is DsaPublicKeyParameters) {
            DsaPublicKeyParameters dsaParameters =
              (DsaPublicKeyParameters)parameters;

            builder.AddStringBlob(PublicKeyAlgorithm.SSH_DSS.GetIdentifierString());
            builder.AddBigIntBlob(dsaParameters.Parameters.P);
            builder.AddBigIntBlob(dsaParameters.Parameters.Q);
            builder.AddBigIntBlob(dsaParameters.Parameters.G);
            builder.AddBigIntBlob(dsaParameters.Y);
              } else if (parameters is ECPublicKeyParameters) {
            ECPublicKeyParameters ecdsaParameters =
              (ECPublicKeyParameters)parameters;

            string algorithm;
            switch (ecdsaParameters.Parameters.Curve.FieldSize) {
              case 256:
            algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP256.GetIdentifierString();
            break;
              case 384:
            algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP384.GetIdentifierString();
            break;
              case 521:
            algorithm = PublicKeyAlgorithm.ECDSA_SHA2_NISTP521.GetIdentifierString();
            break;
              default:
            throw new ArgumentException("Unsupported EC size: " +
              ecdsaParameters.Parameters.Curve.FieldSize);
            }
            builder.AddStringBlob(algorithm);
            algorithm =
              algorithm.Replace(PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_PREFIX,
              string.Empty);
            builder.AddStringBlob(algorithm);
            builder.AddBlob(ecdsaParameters.Q.GetEncoded());
              } else if (parameters is Ed25519PublicKeyParameter) {
              builder.AddStringBlob(PublicKeyAlgorithm.ED25519.GetIdentifierString());
              builder.AddBlob(((Ed25519PublicKeyParameter)parameters).Key);
              } else {
            throw new ArgumentException(parameters.GetType() + " is not supported");
              }
              byte[] result = builder.GetBlob();
              builder.Clear();
              return result;
        }
Пример #7
0
 /// <summary>
 /// prepares a lock or unlock message with specified password
 /// </summary>
 private void PrepareLockMessage(bool aLock, string aPassword)
 {
   BlobBuilder builder = new BlobBuilder();
   builder.AddStringBlob(aPassword);
   if (aLock) {
     builder.InsertHeader(Agent.Message.SSH_AGENTC_LOCK);
   } else {
     builder.InsertHeader(Agent.Message.SSH_AGENTC_UNLOCK);
   }
   PrepareMessage(builder);
 }
        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);
            }
        }
Пример #9
0
        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);
            }
        }
Пример #10
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;
 }
Пример #11
0
    public void TestAnswerSSH2_AGENTC_SIGN_REQUEST()
    {
      const string signatureData = "this is the data that gets signed";
      byte[] signatureDataBytes = Encoding.UTF8.GetBytes(signatureData);
      BlobBuilder builder = new BlobBuilder();

      Agent agent = new TestAgent(allKeys);
      Agent.BlobHeader header;
      byte[] signatureBlob;
      BlobParser signatureParser;
      string algorithm;
      byte[] signature;
      ISigner signer;
      bool signatureOk;
      BigInteger r, s;
      DerSequence seq;

      /* test signatures */

      foreach (ISshKey key in allKeys.Where(key => key.Version == SshVersion.SSH2)) {
        builder.Clear();
        builder.AddBlob(key.GetPublicKeyBlob());
        builder.AddStringBlob(signatureData);
        builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST);
        PrepareMessage(builder);
        agent.AnswerMessage(stream);
        RewindStream();

        /* check that proper response type was received */
        header = parser.ReadHeader();
        Assert.That(header.Message,
                    Is.EqualTo(Agent.Message.SSH2_AGENT_SIGN_RESPONSE));
        signatureBlob = parser.ReadBlob();
        signatureParser = new BlobParser(signatureBlob);
        algorithm = signatureParser.ReadString();
        Assert.That(algorithm, Is.EqualTo(key.Algorithm.GetIdentifierString()));
        signature = signatureParser.ReadBlob();
        if (key.Algorithm == PublicKeyAlgorithm.SSH_RSA) {
          Assert.That(signature.Length == key.Size / 8);
        } else if (key.Algorithm == PublicKeyAlgorithm.SSH_DSS) {
          Assert.That(signature.Length, Is.EqualTo(40));
          r = new BigInteger(1, signature, 0, 20);
          s = new BigInteger(1, signature, 20, 20);
          seq = new DerSequence(new DerInteger(r), new DerInteger(s));
          signature = seq.GetDerEncoded();
        } else if (key.Algorithm == PublicKeyAlgorithm.ECDSA_SHA2_NISTP256 ||
          key.Algorithm == PublicKeyAlgorithm.ECDSA_SHA2_NISTP384 ||
          key.Algorithm == PublicKeyAlgorithm.ECDSA_SHA2_NISTP521) {
          Assert.That(signature.Length, Is.AtLeast(key.Size / 4 + 8));
          Assert.That(signature.Length, Is.AtMost(key.Size / 4 + 10));
          BlobParser sigParser = new BlobParser(signature);
          r = new BigInteger(sigParser.ReadBlob());
          s = new BigInteger(sigParser.ReadBlob());
          seq = new DerSequence(new DerInteger(r), new DerInteger(s));
          signature = seq.GetDerEncoded();
        } else if (key.Algorithm == PublicKeyAlgorithm.ED25519) {
            Assert.That(signature.Length, Is.EqualTo(64));
        }
        signer = key.GetSigner();
        signer.Init(false, key.GetPublicKeyParameters());
        signer.BlockUpdate(signatureDataBytes, 0, signatureDataBytes.Length);
        signatureOk = signer.VerifySignature(signature);
        Assert.That(signatureOk, Is.True, "invalid signature");
        Assert.That(header.BlobLength, Is.EqualTo(stream.Position - 4));
      }

      /* test DSA key old signature format */

      builder.Clear();
      builder.AddBlob(dsaKey.GetPublicKeyBlob());
      builder.AddStringBlob(signatureData);
      builder.AddInt((uint)Agent.SignRequestFlags.SSH_AGENT_OLD_SIGNATURE);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.Message,
                  Is.EqualTo(Agent.Message.SSH2_AGENT_SIGN_RESPONSE));
      signatureBlob = parser.ReadBlob();
      signatureParser = new BlobParser(signatureBlob);
      signature = signatureParser.ReadBlob();
      Assert.That(signature.Length == 40);
      r = new BigInteger(1, signature, 0, 20);
      s = new BigInteger(1, signature, 20, 20);
      seq = new DerSequence(new DerInteger(r), new DerInteger(s));
      signature = seq.GetDerEncoded();
      signer = dsaKey.GetSigner();
      signer.Init(false, dsaKey.GetPublicKeyParameters());
      signer.BlockUpdate(signatureDataBytes, 0, signatureDataBytes.Length);
      signatureOk = signer.VerifySignature(signature);
      Assert.That(signatureOk, Is.True, "invalid signature");
      Assert.That(header.BlobLength, Is.EqualTo(stream.Position - 4));

      /* test key not found */

      agent = new TestAgent();
      builder.Clear();
      builder.AddBlob(dsaKey.GetPublicKeyBlob());
      builder.AddStringBlob(signatureData);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      Agent.BlobHeader header2 = parser.ReadHeader();
      Assert.That(header2.BlobLength, Is.EqualTo(1));
      Assert.That(header2.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE));

      /* test confirm constraint */

      agent = new TestAgent();
      Agent.KeyConstraint testConstraint = new Agent.KeyConstraint();
      testConstraint.Type = Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM;
      SshKey testKey = dsaKey.Clone();
      bool confirmCallbackReturnValue = false;
      agent.ConfirmUserPermissionCallback = delegate(ISshKey k, Process p)
      {
        return confirmCallbackReturnValue;
      };
      testKey.AddConstraint(testConstraint);
      agent.AddKey(testKey);
      builder.Clear();
      builder.AddBlob(dsaKey.GetPublicKeyBlob());
      builder.AddStringBlob(signatureData);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_SIGN_REQUEST);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header2 = parser.ReadHeader();
      Assert.That(header2.BlobLength, Is.EqualTo(1));
      Assert.That(header2.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE));
      confirmCallbackReturnValue = true;
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header2 = parser.ReadHeader();
      Assert.That(header2.BlobLength, Is.Not.EqualTo(1));
      Assert.That(header2.Message, Is.EqualTo(Agent.Message.SSH2_AGENT_SIGN_RESPONSE));
    }
Пример #12
0
    public void TestAnswerSSH2_AGENTC_ADD_ID_CONSTRAINED()
    {
      /* most code is shared with SSH2_AGENTC_ADD_IDENTITY, so we just
       * need to test the differences */

      Agent.ConfirmUserPermissionDelegate confirmCallback =
        delegate(ISshKey k, Process p) { return true; };

      Agent agent = new TestAgent();

      /* test that no confirmation callback returns failure */

      BlobBuilder builder = new BlobBuilder();
      RsaPrivateCrtKeyParameters rsaParameters =
        (RsaPrivateCrtKeyParameters)rsaKey.GetPrivateKeyParameters();
      builder.AddStringBlob(rsaKey.Algorithm.GetIdentifierString());
      builder.AddBigIntBlob(rsaParameters.Modulus);
      builder.AddBigIntBlob(rsaParameters.PublicExponent);
      builder.AddBigIntBlob(rsaParameters.Exponent);
      builder.AddBigIntBlob(rsaParameters.QInv);
      builder.AddBigIntBlob(rsaParameters.P);
      builder.AddBigIntBlob(rsaParameters.Q);
      builder.AddStringBlob(rsaKey.Comment);
      //save blob so far so we don't have to repeat later.
      byte[] commonBlob = builder.GetBlob();
      builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      Agent.BlobHeader header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE));

      /* test adding key with confirm constraint */

      agent = new TestAgent();
      agent.ConfirmUserPermissionCallback = confirmCallback;
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      ISshKey returnedKey = agent.GetAllKeys().First();
      Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(1));
      Assert.That(returnedKey.Constraints[0].Type,
        Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM));
      Assert.That(returnedKey.Constraints[0].Data, Is.Null);

      /* test adding key with lifetime constraint */

      agent = new TestAgent();
      builder.Clear();
      builder.AddBytes(commonBlob);
      builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME);
      builder.AddInt(10);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      returnedKey = agent.GetAllKeys().First();
      Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(1));
      Assert.That(returnedKey.Constraints[0].Type,
        Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME));
      Assert.That(returnedKey.Constraints[0].Data.GetType(),
        Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME.GetDataType()));
      Assert.That(returnedKey.Constraints[0].Data, Is.EqualTo(10));

      /* test adding key with multiple constraints */

      agent = new TestAgent();
      agent.ConfirmUserPermissionCallback = confirmCallback;
      builder.Clear();
      builder.AddBytes(commonBlob);
      builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
      builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME);
      builder.AddInt(10);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      returnedKey = agent.GetAllKeys().First();
      Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(2));
      Assert.That(returnedKey.Constraints[0].Type,
        Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM));
      Assert.That(returnedKey.Constraints[0].Data, Is.Null);
      Assert.That(returnedKey.Constraints[1].Type,
        Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME));
      Assert.That(returnedKey.Constraints[1].Data, Is.EqualTo(10));

      /* test adding key with multiple constraints in different order */

      agent = new TestAgent();
      agent.ConfirmUserPermissionCallback = confirmCallback;
      builder.Clear();
      builder.AddBytes(commonBlob);
      builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME);
      builder.AddInt(10);
      builder.AddByte((byte)Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      returnedKey = agent.GetAllKeys().First();
      Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(2));
      Assert.That(returnedKey.Constraints[0].Type,
        Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME));
      Assert.That(returnedKey.Constraints[0].Data, Is.EqualTo(10));
      Assert.That(returnedKey.Constraints[1].Type,
        Is.EqualTo(Agent.KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM));
      Assert.That(returnedKey.Constraints[1].Data, Is.Null);
    }
Пример #13
0
    public void TestAnswerSSH2_AGENTC_ADD_IDENTITY()
    {
      Agent agent = new TestAgent();

      /* test adding RSA key */

      BlobBuilder builder = new BlobBuilder();
      RsaPrivateCrtKeyParameters rsaParameters =
        (RsaPrivateCrtKeyParameters)rsaKey.GetPrivateKeyParameters();
      builder.AddStringBlob(rsaKey.Algorithm.GetIdentifierString());
      builder.AddBigIntBlob(rsaParameters.Modulus);
      builder.AddBigIntBlob(rsaParameters.PublicExponent);
      builder.AddBigIntBlob(rsaParameters.Exponent);
      builder.AddBigIntBlob(rsaParameters.QInv);
      builder.AddBigIntBlob(rsaParameters.P);
      builder.AddBigIntBlob(rsaParameters.Q);
      builder.AddStringBlob(rsaKey.Comment);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      Agent.BlobHeader header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      ISshKey returnedKey = agent.GetAllKeys().First();
      Assert.That(returnedKey.GetPublicKeyParameters(),
                  Is.InstanceOf<RsaKeyParameters>());
      Assert.That(returnedKey.GetPrivateKeyParameters(),
                  Is.InstanceOf<RsaKeyParameters>());
      Assert.That(returnedKey.Size, Is.EqualTo(rsaKey.Size));
      Assert.That(returnedKey.Comment, Is.EqualTo(rsaKey.Comment));
      Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(rsaKey.GetMD5Fingerprint()));

      /* test adding DSA key */

      agent = new TestAgent();
      builder.Clear();
      DsaPublicKeyParameters dsaPublicParameters =
        (DsaPublicKeyParameters)dsaKey.GetPublicKeyParameters();
      DsaPrivateKeyParameters dsaPrivateParameters =
        (DsaPrivateKeyParameters)dsaKey.GetPrivateKeyParameters();
      builder.AddStringBlob(dsaKey.Algorithm.GetIdentifierString());
      builder.AddBigIntBlob(dsaPublicParameters.Parameters.P);
      builder.AddBigIntBlob(dsaPublicParameters.Parameters.Q);
      builder.AddBigIntBlob(dsaPublicParameters.Parameters.G);
      builder.AddBigIntBlob(dsaPublicParameters.Y);
      builder.AddBigIntBlob(dsaPrivateParameters.X);
      builder.AddStringBlob(dsaKey.Comment);
      builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      returnedKey = agent.GetAllKeys().First();
      Assert.That(returnedKey.GetPublicKeyParameters(),
                  Is.InstanceOf<DsaKeyParameters>());
      Assert.That(returnedKey.GetPrivateKeyParameters(),
                  Is.InstanceOf<DsaKeyParameters>());
      Assert.That(returnedKey.Size, Is.EqualTo(dsaKey.Size));
      Assert.That(returnedKey.Comment, Is.EqualTo(dsaKey.Comment));
      Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(dsaKey.GetMD5Fingerprint()));

      /* test adding ECDSA keys */

      List<ISshKey> ecdsaKeysList = new List<ISshKey>();
      ecdsaKeysList.Add(ecdsa256Key);
      ecdsaKeysList.Add(ecdsa384Key);
      ecdsaKeysList.Add(ecdsa521Key);
      foreach (ISshKey key in ecdsaKeysList) {
        agent = new TestAgent();
        builder.Clear();
        ECPublicKeyParameters ecdsaPublicParameters =
          (ECPublicKeyParameters)key.GetPublicKeyParameters();
        ECPrivateKeyParameters ecdsaPrivateParameters =
          (ECPrivateKeyParameters)key.GetPrivateKeyParameters();
        string ecdsaAlgorithm = key.Algorithm.GetIdentifierString();
        builder.AddStringBlob(ecdsaAlgorithm);
        ecdsaAlgorithm =
          ecdsaAlgorithm.Replace(PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_PREFIX,
          string.Empty);
        builder.AddStringBlob(ecdsaAlgorithm);
        builder.AddBlob(ecdsaPublicParameters.Q.GetEncoded());
        builder.AddBigIntBlob(ecdsaPrivateParameters.D);
        builder.AddStringBlob(key.Comment);
        builder.InsertHeader(Agent.Message.SSH2_AGENTC_ADD_IDENTITY);
        PrepareMessage(builder);
        agent.AnswerMessage(stream);
        RewindStream();
        header = parser.ReadHeader();
        Assert.That(header.BlobLength, Is.EqualTo(1));
        Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
        returnedKey = agent.GetAllKeys().First();
        Assert.That(returnedKey.GetPublicKeyParameters(),
                    Is.InstanceOf<ECPublicKeyParameters>());
        Assert.That(returnedKey.GetPrivateKeyParameters(),
                    Is.InstanceOf<ECPrivateKeyParameters>());
        Assert.That(returnedKey.Size, Is.EqualTo(key.Size));
        Assert.That(returnedKey.Comment, Is.EqualTo(key.Comment));
        Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(key.GetMD5Fingerprint()));
        Assert.That(returnedKey.Constraints.Count(), Is.EqualTo(0));
      }

      /* test adding key that already is in KeyList does not create duplicate */
      int startingCount = agent.GetAllKeys().Count();
      Assert.That(startingCount, Is.Not.EqualTo(0));
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      Assert.That(agent.GetAllKeys().Count(), Is.EqualTo(startingCount));

      /* test locked => failure */
      agent = new TestAgent();
      agent.Lock(new byte[0]);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_FAILURE));
      Assert.That(agent.GetAllKeys().Count, Is.EqualTo(0));
    }
Пример #14
0
    public void TestAnswerSSH1_AGENTC_ADD_RSA_IDENTITY()
    {
      Agent agent = new TestAgent();

      /* test adding RSA key */

      BlobBuilder builder = new BlobBuilder();
      RsaPrivateCrtKeyParameters rsaParameters =
        (RsaPrivateCrtKeyParameters)rsa1Key.GetPrivateKeyParameters();
      builder.AddInt(rsa1Key.Size);
      builder.AddSsh1BigIntBlob(rsaParameters.Modulus);
      builder.AddSsh1BigIntBlob(rsaParameters.PublicExponent);
      builder.AddSsh1BigIntBlob(rsaParameters.Exponent);
      builder.AddSsh1BigIntBlob(rsaParameters.QInv);
      builder.AddSsh1BigIntBlob(rsaParameters.P);
      builder.AddSsh1BigIntBlob(rsaParameters.Q);
      builder.AddStringBlob(rsa1Key.Comment);
      builder.InsertHeader(Agent.Message.SSH1_AGENTC_ADD_RSA_IDENTITY);
      PrepareMessage(builder);
      agent.AnswerMessage(stream);
      RewindStream();
      Agent.BlobHeader header = parser.ReadHeader();
      Assert.That(header.BlobLength, Is.EqualTo(1));
      Assert.That(header.Message, Is.EqualTo(Agent.Message.SSH_AGENT_SUCCESS));
      ISshKey returnedKey = agent.GetAllKeys().First();
      Assert.That(returnedKey.GetPublicKeyParameters(),
                  Is.InstanceOf<RsaKeyParameters>());
      Assert.That(returnedKey.GetPrivateKeyParameters(),
                  Is.InstanceOf<RsaKeyParameters>());
      Assert.That(returnedKey.Size, Is.EqualTo(rsa1Key.Size));
      Assert.That(returnedKey.Comment, Is.EqualTo(rsa1Key.Comment));
      Assert.That(returnedKey.GetMD5Fingerprint(), Is.EqualTo(rsa1Key.GetMD5Fingerprint()));
    }
Пример #15
0
        public override void Serialize(Stream aStream, object aObject)
        {
            /* check for required parameters */
            if (aStream == null)
            {
                throw new ArgumentNullException("aStream");
            }

            if (aObject == null)
            {
                throw new ArgumentNullException("aObject");
            }

            PasswordFinder pwFinder = null;

            if (GetPassphraseCallbackMethod != null)
            {
                pwFinder = new PasswordFinder(GetPassphraseCallbackMethod);
            }
            PinnedArray <char> passphrase = null;

            if (pwFinder != null)
            {
                passphrase      = new PinnedArray <char>(0);
                passphrase.Data = pwFinder.GetPassword();
            }

            byte cipherType;

            if (passphrase == null || passphrase.Data.Length == 0)
            {
                cipherType = SSH_CIPHER_NONE;
            }
            else
            {
                cipherType = SSH_CIPHER_3DES;
            }

            BlobBuilder builder = new BlobBuilder();

            ISshKey          sshKey          = aObject as ISshKey;
            RsaKeyParameters publicKeyParams = sshKey.GetPublicKeyParameters()
                                               as RsaKeyParameters;
            RsaPrivateCrtKeyParameters privateKeyParams = sshKey.GetPrivateKeyParameters()
                                                          as RsaPrivateCrtKeyParameters;

            /* writing info headers */
            builder.AddBytes(Encoding.ASCII.GetBytes(FILE_HEADER_LINE + "\n"));
            builder.AddUInt8(0);          //end of string
            builder.AddUInt8(cipherType); //cipher
            builder.AddInt(0);            //reserved

            /* writing public key */
            builder.AddInt(sshKey.Size);
            builder.AddSsh1BigIntBlob(publicKeyParams.Modulus);
            builder.AddSsh1BigIntBlob(publicKeyParams.Exponent);
            builder.AddStringBlob(sshKey.Comment);

            /* writing private key */
            BlobBuilder privateKeyBuilder = new BlobBuilder();

            /* adding some control values */
            Random random = new Random();

            byte[] resultCheck = new byte[2];
            random.NextBytes(resultCheck);

            privateKeyBuilder.AddUInt8(resultCheck[0]);
            privateKeyBuilder.AddUInt8(resultCheck[1]);
            privateKeyBuilder.AddUInt8(resultCheck[0]);
            privateKeyBuilder.AddUInt8(resultCheck[1]);
            privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.Exponent);
            privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.DQ);
            privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.P);
            privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.Q);

            if (cipherType == SSH_CIPHER_NONE)
            {
                /* plain-text */
                builder.AddBytes(privateKeyBuilder.GetBlobAsPinnedByteArray().Data);
            }
            else
            {
                byte[] keydata;
                using (MD5 md5 = MD5.Create()) {
                    keydata = md5.ComputeHash(Encoding.ASCII.GetBytes(passphrase.Data));
                }

                /* encryption */
                DesSsh1Engine desEngine = new DesSsh1Engine();
                desEngine.Init(true, new KeyParameter(keydata));

                BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(desEngine);
                byte[] ouputBuffer = bufferedBlockCipher.ProcessBytes(
                    privateKeyBuilder.GetBlobAsPinnedByteArray().Data);

                builder.AddBytes(ouputBuffer);

                passphrase.Dispose();
            }

            /* writing result to file */
            var builderOutput = builder.GetBlobAsPinnedByteArray();

            aStream.Write(builderOutput.Data, 0, builderOutput.Data.Length);
            aStream.Close();
        }
Пример #16
0
        /// <summary>
        /// reads OpenSSH formatted public key blob and creates
        /// an AsymmetricKeyParameter object
        /// </summary>
        /// <returns>AsymmetricKeyParameter containing the public key</returns>
        public AsymmetricKeyParameter ReadSsh2PublicKeyData(out OpensshCertificate cert)
        {
            cert = null;
            var algorithm   = Encoding.UTF8.GetString(ReadBlob());
            var certBuilder = new BlobBuilder();

            certBuilder.AddStringBlob(algorithm);

            switch (algorithm)
            {
            case PublicKeyAlgorithmExt.ALGORITHM_RSA_KEY: {
                var n = new BigInteger(1, ReadBlob()); // modulus
                var e = new BigInteger(1, ReadBlob()); // exponent
                if (n.BitLength < e.BitLength)
                {
                    // In some cases, the modulus is first. We can always tell because
                    // it is significantly larget than the exponent.
                    return(new RsaKeyParameters(false, e, n));
                }
                return(new RsaKeyParameters(false, n, e));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_RSA_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    return(certParser.ReadSsh2PublicKeyData(out cert));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var e = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(e);
                    var n = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(n);

                    cert = ReadCertificate(certBuilder);

                    return(new RsaKeyParameters(false, n, e));
                }
            }

            case PublicKeyAlgorithmExt.ALGORITHM_DSA_KEY: {
                var p = new BigInteger(1, ReadBlob());
                var q = new BigInteger(1, ReadBlob());
                var g = new BigInteger(1, ReadBlob());
                var y = new BigInteger(1, ReadBlob());

                var dsaParams = new DsaParameters(p, q, g);
                return(new DsaPublicKeyParameters(y, dsaParams));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_DSA_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    return(certParser.ReadSsh2PublicKeyData(out cert));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var p = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(p);
                    var q = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(q);
                    var g = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(g);
                    var y = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(y);

                    cert = ReadCertificate(certBuilder);

                    var dsaParams = new DsaParameters(p, q, g);
                    return(new DsaPublicKeyParameters(y, dsaParams));
                }
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP256_KEY:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP384_KEY:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP521_KEY: {
                var curveName = ReadString();
                var publicKey = ReadBlob();

                var x9Params     = SecNamedCurves.GetByName(EcCurveToAlgorithm(curveName));
                var domainParams = new ECDomainParameters(x9Params.Curve, x9Params.G, x9Params.N, x9Params.H);
                var point        = x9Params.Curve.DecodePoint(publicKey);
                return(new ECPublicKeyParameters(point, domainParams));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP256_CERT_V1:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP384_CERT_V1:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP521_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    return(certParser.ReadSsh2PublicKeyData(out cert));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var curveName = ReadString();
                    certBuilder.AddStringBlob(curveName);
                    var publicKey = ReadBlob();
                    certBuilder.AddBlob(publicKey);

                    cert = ReadCertificate(certBuilder);

                    var x9Params     = SecNamedCurves.GetByName(EcCurveToAlgorithm(curveName));
                    var domainParams = new ECDomainParameters(x9Params.Curve, x9Params.G, x9Params.N, x9Params.H);
                    var point        = x9Params.Curve.DecodePoint(publicKey);

                    return(new ECPublicKeyParameters(point, domainParams));
                }
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ED25519: {
                var publicKey = ReadBlob();
                return(new Ed25519PublicKeyParameter(publicKey));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ED25519_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    certParser.ReadSsh2PublicKeyData(out cert);
                    var publicKey = ReadBlob();

                    return(new Ed25519PublicKeyParameter(publicKey));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var publicKey = ReadBlob();
                    certBuilder.AddBlob(publicKey);

                    cert = ReadCertificate(certBuilder);

                    return(new Ed25519PublicKeyParameter(publicKey));
                }
            }

            default:
                // unsupported encryption algorithm
                throw new Exception("Unsupported algorithm");
            }
        }
Пример #17
0
 public void TestAddString()
 {
     BlobBuilder builder = new BlobBuilder();
       string value = "test string";
       builder.AddStringBlob(value);
       byte[] valueBytes = Encoding.UTF8.GetBytes(value);
       byte[] expected = new byte[valueBytes.Length + 4];
       Array.Copy(valueBytes.Length.ToBytes(), expected, 4);
       Array.Copy(valueBytes, 0, expected, 4, valueBytes.Length);
       Assert.That(builder.GetBlob(), Is.EqualTo(expected));
 }
Пример #18
0
        /// <summary>
        /// Answers the message.
        /// </summary>
        /// <param name='messageStream'>Message stream.</param>
        /// <param name="process">The calling process or <c>null</c> if the process
        /// could not be obtained.</param>
        /// <remarks>code based on winpgnt.c from PuTTY source code</remarks>
        public void AnswerMessage(Stream messageStream, Process process = null)
        {
            if (messageStream.CanTimeout)
            {
                messageStream.ReadTimeout = 5000;
            }
            var        messageParser   = new BlobParser(messageStream);
            var        responseBuilder = new BlobBuilder();
            BlobHeader header;

            try {
                header = messageParser.ReadHeader();

                if (MessageReceived != null)
                {
                    var eventArgs = new MessageReceivedEventArgs(header);
                    MessageReceived(this, eventArgs);
                    if (eventArgs.Fail)
                    {
                        throw new Exception();
                    }
                }
            } catch (Exception) {
                header         = new BlobHeader();
                header.Message = Message.UNKNOWN;
                // this will cause the switch statement below to use the default case
                // which returns an error to the stream.
            }

            switch (header.Message)
            {
            case Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
                /*
                 * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
                 */
                try {
                    if (header.BlobLength > 1)
                    {
                        // ruby net-ssh tries to send a SSH2_AGENT_REQUEST_VERSION message
                        // which has the same id number as SSH1_AGENTC_REQUEST_RSA_IDENTITIES
                        // with a string tacked on. We need to read the string from the
                        // stream, but it is not used for anything.
                        messageParser.ReadString();
                    }
                    var keyList = ListKeys(SshVersion.SSH1);
                    if (FilterKeyListCallback != null)
                    {
                        keyList = FilterKeyListCallback(keyList);
                    }
                    foreach (SshKey key in keyList)
                    {
                        responseBuilder.AddBytes(key.GetPublicKeyBlob());
                        responseBuilder.AddStringBlob(key.Comment);
                    }
                    responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER,
                                                 keyList.Count);
                    // TODO may want to check that there is enough room in the message stream
                    break; // succeeded
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH2_AGENTC_REQUEST_IDENTITIES:
                /*
                 * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
                 */
                try {
                    var keyList = ListKeys(SshVersion.SSH2);
                    if (FilterKeyListCallback != null)
                    {
                        keyList = FilterKeyListCallback(keyList);
                    }
                    foreach (SshKey key in keyList)
                    {
                        responseBuilder.AddBlob(key.GetPublicKeyBlob());
                        responseBuilder.AddStringBlob(key.Comment);
                    }
                    responseBuilder.InsertHeader(Message.SSH2_AGENT_IDENTITIES_ANSWER,
                                                 keyList.Count);
                    // TODO may want to check that there is enough room in the message stream
                    break; // succeeded
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_RSA_CHALLENGE:
                /*
                 * Reply with either SSH1_AGENT_RSA_RESPONSE or
                 * SSH_AGENT_FAILURE, depending on whether we have that key
                 * or not.
                 */

                try {
                    //Reading publicKey information
                    var publicKeyParams = messageParser.ReadSsh1PublicKeyData(true);

                    //Searching for Key here
                    var matchingKey = mKeyList.Where(key => key.Version == SshVersion.SSH1 &&
                                                     (key.GetPublicKeyParameters().Equals(publicKeyParams))).Single();

                    //Reading challenge
                    var encryptedChallenge = messageParser.ReadSsh1BigIntBlob();
                    var sessionId          = messageParser.ReadBytes(16);

                    //Checking responseType field
                    if (messageParser.ReadUInt32() != 1)
                    {
                        goto default; //responseType !=1  is not longer supported
                    }

                    //Answering to the challenge
                    var engine = new Pkcs1Encoding(new RsaEngine());
                    engine.Init(false /* decrypt */, matchingKey.GetPrivateKeyParameters());

                    var decryptedChallenge = engine.ProcessBlock(encryptedChallenge,
                                                                 0, encryptedChallenge.Length);

                    using (MD5 md5 = MD5.Create()) {
                        var md5Buffer = new byte[48];
                        decryptedChallenge.CopyTo(md5Buffer, 0);
                        sessionId.CopyTo(md5Buffer, 32);

                        responseBuilder.AddBytes(md5.ComputeHash(md5Buffer));
                        responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_RESPONSE);
                        break;
                    }
                } catch (InvalidOperationException) {
                    // this is expected if there is not a matching key
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }

                goto default; // failed

            case Message.SSH2_AGENTC_SIGN_REQUEST:
                /*
                 * Reply with either SSH2_AGENT_SIGN_RESPONSE or SSH_AGENT_FAILURE,
                 * depending on whether we have that key or not.
                 */
                try {
                    var keyBlob = messageParser.ReadBlob();
                    var reqData = messageParser.ReadBlob();
                    var flags   = new SignRequestFlags();
                    try {
                        // usually, there are no flags, so parser will throw
                        flags = (SignRequestFlags)messageParser.ReadUInt32();
                    } catch { }

                    var matchingKey =
                        mKeyList.Where(key => key.Version == SshVersion.SSH2 &&
                                       key.GetPublicKeyBlob().SequenceEqual(keyBlob)).First();
                    var confirmConstraints = matchingKey.Constraints
                                             .Where(constraint => constraint.Type ==
                                                    KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
                    if (confirmConstraints.Count() > 0)
                    {
                        if (!ConfirmUserPermissionCallback.Invoke(matchingKey, process))
                        {
                            goto default;
                        }
                    }

                    /* create signature */
                    var signKey = matchingKey;
                    var signer  = signKey.GetSigner();
                    var algName = signKey.Algorithm.GetIdentifierString();
                    signer.Init(true, signKey.GetPrivateKeyParameters());
                    signer.BlockUpdate(reqData, 0, reqData.Length);
                    byte[] signature = signer.GenerateSignature();
                    signature = signKey.FormatSignature(signature);
                    BlobBuilder signatureBuilder = new BlobBuilder();
                    if (!flags.HasFlag(SignRequestFlags.SSH_AGENT_OLD_SIGNATURE))
                    {
                        signatureBuilder.AddStringBlob(algName);
                    }
                    signatureBuilder.AddBlob(signature);
                    responseBuilder.AddBlob(signatureBuilder.GetBlob());
                    responseBuilder.InsertHeader(Message.SSH2_AGENT_SIGN_RESPONSE);
                    try {
                        KeyUsed(this, new KeyUsedEventArgs(signKey, process));
                    } catch { }
                    break; // succeeded
                } catch (InvalidOperationException) {
                    // this is expected if there is not a matching key
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failure

            case Message.SSH1_AGENTC_ADD_RSA_IDENTITY:
            case Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED:
                /*
                 * Add to the list and return SSH_AGENT_SUCCESS, or
                 * SSH_AGENT_FAILURE if the key was malformed.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                bool ssh1constrained = (header.Message == Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED);

                try {
                    var publicKeyParams = messageParser.ReadSsh1PublicKeyData(false);
                    var keyPair         = messageParser.ReadSsh1KeyData(publicKeyParams);

                    SshKey key = new SshKey(SshVersion.SSH1, keyPair);
                    key.Comment = messageParser.ReadString();
                    key.Source  = "External client";

                    if (ssh1constrained)
                    {
                        while (messageStream.Position < header.BlobLength + 4)
                        {
                            KeyConstraint constraint = new KeyConstraint();
                            constraint.Type = (KeyConstraintType)messageParser.ReadUInt8();
                            if (constraint.Type ==
                                KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)
                            {
                                constraint.Data = messageParser.ReadUInt32();
                            }
                            key.AddConstraint(constraint);
                        }
                    }
                    AddKey(key);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break;
                } catch (CallbackNullException) {
                    // this is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }

                goto default; // failed

            case Message.SSH2_AGENTC_ADD_IDENTITY:
            case Message.SSH2_AGENTC_ADD_ID_CONSTRAINED:
                /*
                 * Add to the list and return SSH_AGENT_SUCCESS, or
                 * SSH_AGENT_FAILURE if the key was malformed.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                bool constrained = (header.Message ==
                                    Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);

                try {
                    OpensshCertificate cert;
                    var    publicKeyParams = messageParser.ReadSsh2PublicKeyData(out cert);
                    var    keyPair         = messageParser.ReadSsh2KeyData(publicKeyParams);
                    SshKey key             = new SshKey(SshVersion.SSH2, keyPair, null, cert);
                    key.Comment = messageParser.ReadString();
                    key.Source  = "External client";

                    if (constrained)
                    {
                        while (messageStream.Position < header.BlobLength + 4)
                        {
                            KeyConstraint constraint = new KeyConstraint();
                            constraint.Type =
                                (KeyConstraintType)messageParser.ReadUInt8();
                            if (constraint.Type ==
                                KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)
                            {
                                constraint.Data = messageParser.ReadUInt32();
                            }
                            key.AddConstraint(constraint);
                        }
                    }
                    AddKey(key);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break; // success!
                } catch (CallbackNullException) {
                    // this is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY:
            case Message.SSH2_AGENTC_REMOVE_IDENTITY:
                /*
                 * Remove from the list and return SSH_AGENT_SUCCESS, or
                 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
                 * start with.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                SshVersion removeVersion;
                byte[]     rKeyBlob;
                if (header.Message == Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY)
                {
                    removeVersion = SshVersion.SSH1;
                    rKeyBlob      = messageParser.ReadBytes(header.BlobLength - 1);
                }
                else if (header.Message == Message.SSH2_AGENTC_REMOVE_IDENTITY)
                {
                    removeVersion = SshVersion.SSH2;
                    rKeyBlob      = messageParser.ReadBlob();
                }
                else
                {
                    Debug.Fail("Should not get here.");
                    goto default;
                }

                try {
                    var matchingKey        = mKeyList.Get(removeVersion, rKeyBlob);
                    var startKeyListLength = mKeyList.Count;
                    RemoveKey(matchingKey);
                    // only succeed if key was removed
                    if (mKeyList.Count == startKeyListLength - 1)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break; //success!
                    }
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
            case Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
                /*
                 * Remove all SSH-1 or SSH-2 keys.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                SshVersion removeAllVersion;
                if (header.Message == Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES)
                {
                    removeAllVersion = SshVersion.SSH1;
                }
                else if (header.Message == Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES)
                {
                    removeAllVersion = SshVersion.SSH2;
                }
                else
                {
                    Debug.Fail("Should not get here.");
                    goto default;
                }

                try {
                    RemoveAllKeys(removeAllVersion);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break; //success!
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH_AGENTC_LOCK:
                try {
                    var passphrase = new PinnedArray <byte>(messageParser.ReadBlob());
                    try {
                        Lock(passphrase.Data);
                    } finally {
                        passphrase.Clear();
                    }
                    if (IsLocked)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break;
                    }
                } catch (AgentLockedException) {
                    // This is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default;

            case Message.SSH_AGENTC_UNLOCK:
                try {
                    var passphrase = new PinnedArray <byte>(messageParser.ReadBlob());
                    try {
                        Unlock(passphrase.Data);
                    } finally {
                        passphrase.Clear();
                    }
                    if (!IsLocked)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break;
                    }
                } catch (AgentLockedException) {
                    // This is expected
                } catch (PassphraseException) {
                    // This is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default;

            default:
                responseBuilder.Clear();
                responseBuilder.InsertHeader(Message.SSH_AGENT_FAILURE);
                break;
            }
            /* write response to stream */
            if (messageStream.CanSeek)
            {
                messageStream.Position = 0;
            }
            messageStream.Write(responseBuilder.GetBlob(), 0, responseBuilder.Length);
            messageStream.Flush();
        }
Пример #19
0
        private static void VerifyIntegrity(FileData fileData)
        {
            BlobBuilder builder = new BlobBuilder();
              if (fileData.ppkFileVersion != Version.V1) {
            builder.AddStringBlob(fileData.publicKeyAlgorithm.GetIdentifierString());
            builder.AddStringBlob(fileData.privateKeyAlgorithm.GetIdentifierString());
            builder.AddBlob(Encoding.GetEncoding(1252).GetBytes(fileData.comment));
            builder.AddBlob(fileData.publicKeyBlob);
            builder.AddInt(fileData.privateKeyBlob.Data.Length);
              }
              builder.AddBytes(fileData.privateKeyBlob.Data);

              byte[] computedHash;
              SHA1 sha = SHA1.Create();
              if (fileData.isHMAC) {
            HMAC hmac = HMACSHA1.Create();
            if (fileData.passphrase != null) {
              using (PinnedArray<byte> hashData =
                 new PinnedArray<byte>(cMACKeySalt.Length +
                   fileData.passphrase.Length)) {
            Array.Copy(Encoding.UTF8.GetBytes(cMACKeySalt),
                       hashData.Data, cMACKeySalt.Length);
            IntPtr passphrasePtr =
              Marshal.SecureStringToGlobalAllocUnicode(fileData.passphrase);
            for (int i = 0; i < fileData.passphrase.Length; i++) {
              int unicodeChar = Marshal.ReadInt16(passphrasePtr + i * 2);
              byte ansiChar = Util.UnicodeToAnsi(unicodeChar);
              hashData.Data[cMACKeySalt.Length + i] = ansiChar;
              Marshal.WriteByte(passphrasePtr, i * 2, 0);
            }
            Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr);
            hmac.Key = sha.ComputeHash(hashData.Data);
              }
            } else {
              hmac.Key = sha.ComputeHash(Encoding.UTF8.GetBytes(cMACKeySalt));
            }
            computedHash = hmac.ComputeHash(builder.GetBlob());
            hmac.Clear();
              } else {
            computedHash = sha.ComputeHash(builder.GetBlob());
              }
              sha.Clear();
              builder.Clear();

              try {
            int macLength = computedHash.Length;
            bool failed = false;
            if (fileData.privateMAC.Length == macLength) {
              for (int i = 0; i < macLength; i++) {
            if (fileData.privateMAC[i] != computedHash[i]) {
              failed = true;
              break;
            }
              }
            } else {
              failed = true;
            }
            if (failed) {
              // private key data should start with 3 bytes with value 0 if it was
              // properly decrypted or does not require decryption
              if ((fileData.privateKeyBlob.Data[0] == 0) &&
              (fileData.privateKeyBlob.Data[1] == 0) &&
              (fileData.privateKeyBlob.Data[2] == 0)) {
            // so if they bytes are there, passphrase decrypted properly and
            // something else is wrong with the file contents
            throw new PpkFormatterException(PpkFormatterException.PpkErrorType.FileCorrupt);
              } else {
            // if the bytes are not zeros, we assume that the data was not
            // properly decrypted because the passphrase was incorrect.
            throw new PpkFormatterException(PpkFormatterException.PpkErrorType.BadPassphrase);
              }
            }
              } catch {
            throw;
              } finally {
            Array.Clear(computedHash, 0, computedHash.Length);
              }
        }
Пример #20
0
        public override void Serialize(Stream aStream, object aObject)
        {
            /* check for required parameters */
              if (aStream == null) {
            throw new ArgumentNullException("aStream");
              }

              if (aObject == null) {
            throw new ArgumentNullException("aObject");
              }

              PasswordFinder pwFinder = null;
              if (GetPassphraseCallbackMethod != null) {
            pwFinder = new PasswordFinder(GetPassphraseCallbackMethod);
              }
              PinnedArray<char> passphrase = null;
              if (pwFinder != null) {
            passphrase = new PinnedArray<char>(0);
            passphrase.Data = pwFinder.GetPassword();
              }

              byte cipherType;
              if (passphrase == null || passphrase.Data.Length == 0) {
            cipherType = SSH_CIPHER_NONE;
              } else {
            cipherType = SSH_CIPHER_3DES;
              }

              BlobBuilder builder = new BlobBuilder();

              ISshKey sshKey = aObject as ISshKey;
              RsaKeyParameters publicKeyParams = sshKey.GetPublicKeyParameters()
            as RsaKeyParameters;
              RsaPrivateCrtKeyParameters privateKeyParams = sshKey.GetPrivateKeyParameters()
            as RsaPrivateCrtKeyParameters;

              /* writing info headers */
              builder.AddBytes(Encoding.ASCII.GetBytes(FILE_HEADER_LINE + "\n"));
              builder.AddByte(0);          //end of string
              builder.AddByte(cipherType); //cipher
              builder.AddInt(0);           //reserved

              /* writing public key */
              builder.AddInt(sshKey.Size);
              builder.AddSsh1BigIntBlob(publicKeyParams.Modulus);
              builder.AddSsh1BigIntBlob(publicKeyParams.Exponent);
              builder.AddStringBlob(sshKey.Comment);

              /* writing private key */
              BlobBuilder privateKeyBuilder = new BlobBuilder();

              /* adding some control values */
              Random random = new Random();
              byte[] resultCheck = new byte[2];
              random.NextBytes(resultCheck);

              privateKeyBuilder.AddByte(resultCheck[0]);
              privateKeyBuilder.AddByte(resultCheck[1]);
              privateKeyBuilder.AddByte(resultCheck[0]);
              privateKeyBuilder.AddByte(resultCheck[1]);
              privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.Exponent);
              privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.DQ);
              privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.P);
              privateKeyBuilder.AddSsh1BigIntBlob(privateKeyParams.Q);

              if (cipherType == SSH_CIPHER_NONE) {
            /* plain-text */
            builder.AddBytes(privateKeyBuilder.GetBlobAsPinnedByteArray().Data);
              } else {
            byte[] keydata;
            using (MD5 md5 = MD5.Create()) {
              keydata = md5.ComputeHash(Encoding.ASCII.GetBytes(passphrase.Data));
            }

            /* encryption */
            DesSsh1Engine desEngine = new DesSsh1Engine();
            desEngine.Init(true, new KeyParameter(keydata));

            BufferedBlockCipher bufferedBlockCipher = new BufferedBlockCipher(desEngine);
            byte[] ouputBuffer = bufferedBlockCipher.ProcessBytes(
              privateKeyBuilder.GetBlobAsPinnedByteArray().Data);

            builder.AddBytes(ouputBuffer);

            passphrase.Dispose();
              }

              /* writing result to file */
              var builderOutput = builder.GetBlobAsPinnedByteArray();
              aStream.Write(builderOutput.Data, 0, builderOutput.Data.Length);
              aStream.Close();
        }
Пример #21
0
        private static void VerifyIntegrity(FileData fileData)
        {
            BlobBuilder builder = new BlobBuilder();

            if (fileData.ppkFileVersion != Version.V1)
            {
                builder.AddStringBlob(fileData.publicKeyAlgorithm.GetIdentifierString());
                builder.AddStringBlob(fileData.privateKeyAlgorithm.GetIdentifierString());
                builder.AddBlob(Encoding.GetEncoding(1252).GetBytes(fileData.comment));
                builder.AddBlob(fileData.publicKeyBlob);
                builder.AddInt(fileData.privateKeyBlob.Data.Length);
            }
            builder.AddBytes(fileData.privateKeyBlob.Data);

            byte[] computedHash;
            SHA1   sha = SHA1.Create();

            if (fileData.isHMAC)
            {
                HMAC hmac = HMACSHA1.Create();
                if (fileData.passphrase != null)
                {
                    using (PinnedArray <byte> hashData =
                               new PinnedArray <byte>(cMACKeySalt.Length +
                                                      fileData.passphrase.Length)) {
                        Array.Copy(Encoding.UTF8.GetBytes(cMACKeySalt),
                                   hashData.Data, cMACKeySalt.Length);
                        IntPtr passphrasePtr =
                            Marshal.SecureStringToGlobalAllocUnicode(fileData.passphrase);
                        for (int i = 0; i < fileData.passphrase.Length; i++)
                        {
                            int  unicodeChar = Marshal.ReadInt16(passphrasePtr + i * 2);
                            byte ansiChar    = Util.UnicodeToAnsi(unicodeChar);
                            hashData.Data[cMACKeySalt.Length + i] = ansiChar;
                            Marshal.WriteByte(passphrasePtr, i * 2, 0);
                        }
                        Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr);
                        hmac.Key = sha.ComputeHash(hashData.Data);
                    }
                }
                else
                {
                    hmac.Key = sha.ComputeHash(Encoding.UTF8.GetBytes(cMACKeySalt));
                }
                computedHash = hmac.ComputeHash(builder.GetBlob());
                hmac.Clear();
            }
            else
            {
                computedHash = sha.ComputeHash(builder.GetBlob());
            }
            sha.Clear();
            builder.Clear();

            try {
                int  macLength = computedHash.Length;
                bool failed    = false;
                if (fileData.privateMAC.Length == macLength)
                {
                    for (int i = 0; i < macLength; i++)
                    {
                        if (fileData.privateMAC[i] != computedHash[i])
                        {
                            failed = true;
                            break;
                        }
                    }
                }
                else
                {
                    failed = true;
                }
                if (failed)
                {
                    // private key data should start with 3 bytes with value 0 if it was
                    // properly decrypted or does not require decryption
                    if ((fileData.privateKeyBlob.Data[0] == 0) &&
                        (fileData.privateKeyBlob.Data[1] == 0) &&
                        (fileData.privateKeyBlob.Data[2] == 0))
                    {
                        // so if they bytes are there, passphrase decrypted properly and
                        // something else is wrong with the file contents
                        throw new PpkFormatterException(PpkFormatterException.PpkErrorType.FileCorrupt);
                    }
                    else
                    {
                        // if the bytes are not zeros, we assume that the data was not
                        // properly decrypted because the passphrase was incorrect.
                        throw new PpkFormatterException(PpkFormatterException.PpkErrorType.BadPassphrase);
                    }
                }
            } catch {
                throw;
            } finally {
                Array.Clear(computedHash, 0, computedHash.Length);
            }
        }