示例#1
0
        protected override SaslExchangeStatus Exchange(ByteString serverChallenge, out ByteString clientResponse)
        {
            if (Credential == null)
            throw new SaslException("Credential property must be set");

              clientResponse = null;

              if (string.IsNullOrEmpty(Credential.UserName) || string.IsNullOrEmpty(Credential.Password))
            return SaslExchangeStatus.Failed;

              var responseBuilder = new ByteStringBuilder(0x300); // 255(authcid) + 1(NUL) + 255(authzid) + 1(NUL) + 255(passwd)

              responseBuilder.Append(Encoding.UTF8.GetBytes(Credential.Domain ?? string.Empty)); // authcid
              responseBuilder.Append(Smdn.Formats.Octets.NUL);
              responseBuilder.Append(Encoding.UTF8.GetBytes(Credential.UserName)); // authzid
              responseBuilder.Append(Smdn.Formats.Octets.NUL);
              responseBuilder.Append(Encoding.UTF8.GetBytes(Credential.Password)); // passwd

              clientResponse = responseBuilder.ToByteString();

              return SaslExchangeStatus.Succeeded;
        }
示例#2
0
        protected override SaslExchangeStatus Exchange(ByteString serverChallenge, out ByteString clientResponse)
        {
            if (md5 == null)
            throw new ObjectDisposedException(GetType().FullName);
              if (Credential == null)
            throw new SaslException("Credential property must be set");
              if (string.IsNullOrEmpty(ServiceName))
            throw new SaslException("ServiceName property must be set");

              var pairs = ParseChallenge(serverChallenge);

              if (step == 3) {
            /*
             * 2.1.3 Step Three
             */
            if (pairs.ContainsKey("rspauth")) {
              clientResponse = ByteString.CreateEmpty();
              return SaslExchangeStatus.Succeeded;
            }
            else {
              clientResponse = null;
              return SaslExchangeStatus.Failed;
            }
              }

              /*
               * 2.1.1 Step One
               */
              step = 1;
              clientResponse = null;

              if (string.IsNullOrEmpty(Credential.UserName) || string.IsNullOrEmpty(Credential.Password))
            return SaslExchangeStatus.Failed;

              //    algorithm
              //       This directive is required for backwards compatibility with HTTP
              //       Digest., which supports other algorithms. . This directive is
              //       required and MUST appear exactly once; if not present, or if
              //       multiple instances are present, the client should abort the
              //       authentication exchange.
              //
              //         algorithm         = "algorithm" "=" "md5-sess"
              if (!(pairs.ContainsKey("algorithm") && pairs["algorithm"].Equals("md5-sess")))
            return SaslExchangeStatus.Failed; // "algorithm" is missing or unsupported algorithm

              //    charset
              //       This directive, if present, specifies that the server supports
              //       UTF-8 encoding for the username and password. If not present, the
              //       username and password must be encoded in ISO 8859-1 (of which
              //       US-ASCII is a subset). The directive is needed for backwards
              //       compatibility with HTTP Digest, which only supports ISO 8859-1.
              //       This directive may appear at most once; if multiple instances are
              //       present, the client should abort the authentication exchange.
              //
              //         charset           = "charset" "=" "utf-8"
              var charset = (pairs.ContainsKey("charset") && pairs["charset"].Equals("utf-8"))
            ? Encoding.UTF8
            : Encoding.GetEncoding("iso-8859-1");

              ByteString realm, nonce, qop;

              if (!pairs.TryGetValue("realm", out realm))
            return SaslExchangeStatus.Failed;
              if (!pairs.TryGetValue("nonce", out nonce))
            return SaslExchangeStatus.Failed;
              if (!pairs.TryGetValue("qop", out qop))
            return SaslExchangeStatus.Failed;

              qop = new ByteString("auth"); // ignore qop-options

              /*
               * 2.1.2 Step Two
               */
              step = 2;

              //    cnonce
              //       It is RECOMMENDED that it contain at least 64 bits of entropy.
              var cnonce = new ByteString(Cnonce ?? Nonce.Generate(64, true));

              //    nonce-count
              //       The nc-value is the hexadecimal count of the number of requests
              //       (including the current request) that the client has sent with the
              //       nonce value in this request.  For example, in the first request
              //       sent in response to a given nonce value, the client sends
              //       "nc=00000001"
              var nc = new ByteString((1).ToString("X8"));

              //    digest-uri
              //       Indicates the principal name of the service with which the client
              //       wishes to connect, formed from the serv-type, host, and serv-name.
              //       For example, the FTP service on "ftp.example.com" would have a
              //       "digest-uri" value of "ftp/ftp.example.com"; the SMTP server from
              //       the example above would have a "digest-uri" value of
              //       "smtp/mail3.example.com/example.com".
              var digestUri = new ByteString(string.Format("{0}/{1}", ServiceName, Credential.Domain ?? string.Empty));

              //       response-value  =
              //          HEX( KD ( HEX(H(A1)),
              //                  { nonce-value, ":" nc-value, ":",
              //                    cnonce-value, ":", qop-value, ":", HEX(H(A2)) }))
              var responseValue = HexKD(md5,
                                HexHA1(md5, charset, Credential.UserName, realm, Credential.Password, nonce, cnonce, null),
                                nonce,
                                nc,
                                cnonce,
                                qop,
                                HexHA2(md5, qop, digestUri));

              var responseBuilder = new ByteStringBuilder(0x200);

              if (charset == Encoding.UTF8)
            responseBuilder.Append("charset=utf-8,");

              responseBuilder.Append("username=\"");
              responseBuilder.Append(Credential.UserName);
              responseBuilder.Append("\",realm=\"");
              responseBuilder.Append(realm);
              responseBuilder.Append("\",nonce=\"");
              responseBuilder.Append(nonce);
              responseBuilder.Append("\",nc=");
              responseBuilder.Append(nc);
              responseBuilder.Append(",cnonce=\"");
              responseBuilder.Append(cnonce);
              responseBuilder.Append("\",digest-uri=\"");
              responseBuilder.Append(digestUri);
              responseBuilder.Append("\",response=");
              responseBuilder.Append(responseValue);
              responseBuilder.Append(",qop=");
              responseBuilder.Append(qop);

              step = 3;

              clientResponse = responseBuilder.ToByteString();

              return SaslExchangeStatus.Continuing;
        }
示例#3
0
        private static ByteString HexHA2(MD5 h, ByteString qop, ByteString digestUri)
        {
            //    If the "qop" directive's value is "auth", then A2 is:
              //
              //       A2       = { "AUTHENTICATE:", digest-uri-value }
              //
              //    If the "qop" value is "auth-int" or "auth-conf" then A2 is:
              //
              //       A2       = { "AUTHENTICATE:", digest-uri-value,
              //                ":00000000000000000000000000000000" }
              var a2 = new ByteStringBuilder(0x80);

              a2.Append("AUTHENTICATE:");
              a2.Append(digestUri);

              if (qop.EqualsIgnoreCase("auth-int") || qop.EqualsIgnoreCase("auth-conf"))
            a2.Append(":00000000000000000000000000000000");

              return HexH(h, a2.ToByteString());
        }
示例#4
0
        private static ByteString HexKD(MD5 h, ByteString hexHA1, ByteString nonce, ByteString nc, ByteString cnonce, ByteString qop, ByteString hexHA2)
        {
            //       response-value  =
              //          HEX( KD ( HEX(H(A1)),
              //                  { nonce-value, ":" nc-value, ":",
              //                    cnonce-value, ":", qop-value, ":", HEX(H(A2)) }))

              //    Let KD(k, s) be H({k, ":", s}), i.e., the 16 octet hash of the string
              //    k, a colon and the string s.
              var tmp = new ByteStringBuilder(0x100);

              tmp.Append(hexHA1);
              tmp.Append(0x3a);
              tmp.Append(nonce);
              tmp.Append(0x3a);
              tmp.Append(nc);
              tmp.Append(0x3a);
              tmp.Append(cnonce);
              tmp.Append(0x3a);
              tmp.Append(qop);
              tmp.Append(0x3a);
              tmp.Append(hexHA2);

              return HexH(h, tmp.ToByteString());
        }
示例#5
0
        private static ByteString HexHA1(MD5 h, Encoding charset, string username, ByteString realm, string password, ByteString nonce, ByteString cnonce, ByteString authzid)
        {
            //    If authzid is specified, then A1 is
              //
              //       A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
              //            ":", nonce-value, ":", cnonce-value, ":", authzid-value }
              //
              //    If authzid is not specified, then A1 is
              //
              //       A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
              //            ":", nonce-value, ":", cnonce-value }
              var a1 = new ByteStringBuilder(0x100);

              a1.Append(h.ComputeHash(ArrayExtensions.Concat(charset.GetBytes(username),
                                                     new byte[] {0x3a},
                                                     realm.ByteArray,
                                                     new byte[] {0x3a},
                                                     charset.GetBytes(password))));
              a1.Append(0x3a);
              a1.Append(nonce);
              a1.Append(0x3a);
              a1.Append(cnonce);

              if (authzid != null) {
            a1.Append(0x3a);
            a1.Append(authzid);
              }

              return HexH(h, a1.ToByteString());
        }