/// <summary>Read SASL message and negotiated cipher option from server.</summary>
 /// <param name="in">stream to read</param>
 /// <returns>
 /// SaslResponseWithNegotiatedCipherOption SASL message and
 /// negotiated cipher option
 /// </returns>
 /// <exception cref="System.IO.IOException">for any error</exception>
 public static SaslResponseWithNegotiatedCipherOption ReadSaslMessageAndNegotiatedCipherOption
     (InputStream @in)
 {
     DataTransferProtos.DataTransferEncryptorMessageProto proto = DataTransferProtos.DataTransferEncryptorMessageProto
                                                                  .ParseFrom(PBHelper.VintPrefixed(@in));
     if (proto.GetStatus() == DataTransferProtos.DataTransferEncryptorMessageProto.DataTransferEncryptorStatus
         .ErrorUnknownKey)
     {
         throw new InvalidEncryptionKeyException(proto.GetMessage());
     }
     else
     {
         if (proto.GetStatus() == DataTransferProtos.DataTransferEncryptorMessageProto.DataTransferEncryptorStatus
             .Error)
         {
             throw new IOException(proto.GetMessage());
         }
         else
         {
             byte[] response = proto.GetPayload().ToByteArray();
             IList <CipherOption> options = PBHelper.ConvertCipherOptionProtos(proto.GetCipherOptionList
                                                                                   ());
             CipherOption option = null;
             if (options != null && !options.IsEmpty())
             {
                 option = options[0];
             }
             return(new SaslResponseWithNegotiatedCipherOption(response, option));
         }
     }
 }
 /// <summary>Decrypt the key and iv of the negotiated cipher option.</summary>
 /// <param name="option">negotiated cipher option</param>
 /// <param name="sasl">SASL participant representing client</param>
 /// <returns>
 /// CipherOption negotiated cipher option which contains the
 /// decrypted key and iv
 /// </returns>
 /// <exception cref="System.IO.IOException">for any error</exception>
 public static CipherOption Unwrap(CipherOption option, SaslParticipant sasl)
 {
     if (option != null)
     {
         byte[] inKey = option.GetInKey();
         if (inKey != null)
         {
             inKey = sasl.Unwrap(inKey, 0, inKey.Length);
         }
         byte[] outKey = option.GetOutKey();
         if (outKey != null)
         {
             outKey = sasl.Unwrap(outKey, 0, outKey.Length);
         }
         return(new CipherOption(option.GetCipherSuite(), inKey, option.GetInIv(), outKey,
                                 option.GetOutIv()));
     }
     return(null);
 }
 /// <summary>Send SASL message and negotiated cipher option to client.</summary>
 /// <param name="out">stream to receive message</param>
 /// <param name="payload">to send</param>
 /// <param name="option">negotiated cipher option</param>
 /// <exception cref="System.IO.IOException">for any error</exception>
 public static void SendSaslMessageAndNegotiatedCipherOption(OutputStream @out, byte
                                                             [] payload, CipherOption option)
 {
     DataTransferProtos.DataTransferEncryptorMessageProto.Builder builder = DataTransferProtos.DataTransferEncryptorMessageProto
                                                                            .NewBuilder();
     builder.SetStatus(DataTransferProtos.DataTransferEncryptorMessageProto.DataTransferEncryptorStatus
                       .Success);
     if (payload != null)
     {
         builder.SetPayload(ByteString.CopyFrom(payload));
     }
     if (option != null)
     {
         builder.AddCipherOption(PBHelper.Convert(option));
     }
     DataTransferProtos.DataTransferEncryptorMessageProto proto = ((DataTransferProtos.DataTransferEncryptorMessageProto
                                                                    )builder.Build());
     proto.WriteDelimitedTo(@out);
     @out.Flush();
 }
        /// <summary>
        /// Create IOStreamPair of
        /// <see cref="Org.Apache.Hadoop.Crypto.CryptoInputStream"/>
        /// and
        /// <see cref="Org.Apache.Hadoop.Crypto.CryptoOutputStream"/>
        /// </summary>
        /// <param name="conf">the configuration</param>
        /// <param name="cipherOption">negotiated cipher option</param>
        /// <param name="out">underlying output stream</param>
        /// <param name="in">underlying input stream</param>
        /// <param name="isServer">is server side</param>
        /// <returns>IOStreamPair the stream pair</returns>
        /// <exception cref="System.IO.IOException">for any error</exception>
        public static IOStreamPair CreateStreamPair(Configuration conf, CipherOption cipherOption
                                                    , OutputStream @out, InputStream @in, bool isServer)
        {
            if (Log.IsDebugEnabled())
            {
                Log.Debug("Creating IOStreamPair of CryptoInputStream and " + "CryptoOutputStream."
                          );
            }
            CryptoCodec codec = CryptoCodec.GetInstance(conf, cipherOption.GetCipherSuite());

            byte[]      inKey  = cipherOption.GetInKey();
            byte[]      inIv   = cipherOption.GetInIv();
            byte[]      outKey = cipherOption.GetOutKey();
            byte[]      outIv  = cipherOption.GetOutIv();
            InputStream cIn    = new CryptoInputStream(@in, codec, isServer ? inKey : outKey, isServer
                                 ? inIv : outIv);
            OutputStream cOut = new CryptoOutputStream(@out, codec, isServer ? outKey : inKey
                                                       , isServer ? outIv : inIv);

            return(new IOStreamPair(cIn, cOut));
        }
 public SaslResponseWithNegotiatedCipherOption(byte[] payload, CipherOption cipherOption
                                               )
 {
     this.payload      = payload;
     this.cipherOption = cipherOption;
 }
Exemple #6
0
        /// <summary>This method actually executes the client-side SASL handshake.</summary>
        /// <param name="underlyingOut">connection output stream</param>
        /// <param name="underlyingIn">connection input stream</param>
        /// <param name="userName">SASL user name</param>
        /// <param name="saslProps">properties of SASL negotiation</param>
        /// <param name="callbackHandler">for responding to SASL callbacks</param>
        /// <returns>new pair of streams, wrapped after SASL negotiation</returns>
        /// <exception cref="System.IO.IOException">for any error</exception>
        private IOStreamPair DoSaslHandshake(OutputStream underlyingOut, InputStream underlyingIn
                                             , string userName, IDictionary <string, string> saslProps, CallbackHandler callbackHandler
                                             )
        {
            DataOutputStream @out = new DataOutputStream(underlyingOut);
            DataInputStream  @in  = new DataInputStream(underlyingIn);
            SaslParticipant  sasl = SaslParticipant.CreateClientSaslParticipant(userName, saslProps
                                                                                , callbackHandler);

            @out.WriteInt(SaslTransferMagicNumber);
            @out.Flush();
            try
            {
                // Start of handshake - "initial response" in SASL terminology.
                DataTransferSaslUtil.SendSaslMessage(@out, new byte[0]);
                // step 1
                byte[] remoteResponse = DataTransferSaslUtil.ReadSaslMessage(@in);
                byte[] localResponse  = sasl.EvaluateChallengeOrResponse(remoteResponse);
                IList <CipherOption> cipherOptions = null;
                if (DataTransferSaslUtil.RequestedQopContainsPrivacy(saslProps))
                {
                    // Negotiate cipher suites if configured.  Currently, the only supported
                    // cipher suite is AES/CTR/NoPadding, but the protocol allows multiple
                    // values for future expansion.
                    string cipherSuites = conf.Get(DFSConfigKeys.DfsEncryptDataTransferCipherSuitesKey
                                                   );
                    if (cipherSuites != null && !cipherSuites.IsEmpty())
                    {
                        if (!cipherSuites.Equals(CipherSuite.AesCtrNopadding.GetName()))
                        {
                            throw new IOException(string.Format("Invalid cipher suite, %s=%s", DFSConfigKeys.
                                                                DfsEncryptDataTransferCipherSuitesKey, cipherSuites));
                        }
                        CipherOption option = new CipherOption(CipherSuite.AesCtrNopadding);
                        cipherOptions = Lists.NewArrayListWithCapacity(1);
                        cipherOptions.AddItem(option);
                    }
                }
                DataTransferSaslUtil.SendSaslMessageAndNegotiationCipherOptions(@out, localResponse
                                                                                , cipherOptions);
                // step 2 (client-side only)
                SaslResponseWithNegotiatedCipherOption response = DataTransferSaslUtil.ReadSaslMessageAndNegotiatedCipherOption
                                                                      (@in);
                localResponse = sasl.EvaluateChallengeOrResponse(response.payload);
                System.Diagnostics.Debug.Assert(localResponse == null);
                // SASL handshake is complete
                DataTransferSaslUtil.CheckSaslComplete(sasl, saslProps);
                CipherOption cipherOption = null;
                if (sasl.IsNegotiatedQopPrivacy())
                {
                    // Unwrap the negotiated cipher option
                    cipherOption = DataTransferSaslUtil.Unwrap(response.cipherOption, sasl);
                }
                // If negotiated cipher option is not null, we will use it to create
                // stream pair.
                return(cipherOption != null?DataTransferSaslUtil.CreateStreamPair(conf, cipherOption
                                                                                  , underlyingOut, underlyingIn, false) : sasl.CreateStreamPair(@out, @in));
            }
            catch (IOException ioe)
            {
                DataTransferSaslUtil.SendGenericSaslErrorMessage(@out, ioe.Message);
                throw;
            }
        }
        /// <summary>This method actually executes the server-side SASL handshake.</summary>
        /// <param name="underlyingOut">connection output stream</param>
        /// <param name="underlyingIn">connection input stream</param>
        /// <param name="saslProps">properties of SASL negotiation</param>
        /// <param name="callbackHandler">for responding to SASL callbacks</param>
        /// <returns>new pair of streams, wrapped after SASL negotiation</returns>
        /// <exception cref="System.IO.IOException">for any error</exception>
        private IOStreamPair DoSaslHandshake(OutputStream underlyingOut, InputStream underlyingIn
                                             , IDictionary <string, string> saslProps, CallbackHandler callbackHandler)
        {
            DataInputStream  @in  = new DataInputStream(underlyingIn);
            DataOutputStream @out = new DataOutputStream(underlyingOut);
            SaslParticipant  sasl = SaslParticipant.CreateServerSaslParticipant(saslProps, callbackHandler
                                                                                );
            int magicNumber = @in.ReadInt();

            if (magicNumber != SaslTransferMagicNumber)
            {
                throw new InvalidMagicNumberException(magicNumber, dnConf.GetEncryptDataTransfer(
                                                          ));
            }
            try
            {
                // step 1
                byte[] remoteResponse = DataTransferSaslUtil.ReadSaslMessage(@in);
                byte[] localResponse  = sasl.EvaluateChallengeOrResponse(remoteResponse);
                DataTransferSaslUtil.SendSaslMessage(@out, localResponse);
                // step 2 (server-side only)
                IList <CipherOption> cipherOptions = Lists.NewArrayList();
                remoteResponse = DataTransferSaslUtil.ReadSaslMessageAndNegotiationCipherOptions(
                    @in, cipherOptions);
                localResponse = sasl.EvaluateChallengeOrResponse(remoteResponse);
                // SASL handshake is complete
                DataTransferSaslUtil.CheckSaslComplete(sasl, saslProps);
                CipherOption cipherOption = null;
                if (sasl.IsNegotiatedQopPrivacy())
                {
                    // Negotiate a cipher option
                    cipherOption = DataTransferSaslUtil.NegotiateCipherOption(dnConf.GetConf(), cipherOptions
                                                                              );
                    if (cipherOption != null)
                    {
                        if (Log.IsDebugEnabled())
                        {
                            Log.Debug("Server using cipher suite " + cipherOption.GetCipherSuite().GetName());
                        }
                    }
                }
                // If negotiated cipher option is not null, wrap it before sending.
                DataTransferSaslUtil.SendSaslMessageAndNegotiatedCipherOption(@out, localResponse
                                                                              , DataTransferSaslUtil.Wrap(cipherOption, sasl));
                // If negotiated cipher option is not null, we will use it to create
                // stream pair.
                return(cipherOption != null?DataTransferSaslUtil.CreateStreamPair(dnConf.GetConf
                                                                                      (), cipherOption, underlyingOut, underlyingIn, true) : sasl.CreateStreamPair(@out
                                                                                                                                                                   , @in));
            }
            catch (IOException ioe)
            {
                if (ioe is SaslException && ioe.InnerException != null && ioe.InnerException is InvalidEncryptionKeyException)
                {
                    // This could just be because the client is long-lived and hasn't gotten
                    // a new encryption key from the NN in a while. Upon receiving this
                    // error, the client will get a new encryption key from the NN and retry
                    // connecting to this DN.
                    SendInvalidKeySaslErrorMessage(@out, ioe.InnerException.Message);
                }
                else
                {
                    DataTransferSaslUtil.SendGenericSaslErrorMessage(@out, ioe.Message);
                }
                throw;
            }
        }