aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPablo Polvorin <pablo.polvorin@process-one.net>2010-12-01 15:54:58 -0300
committerPablo Polvorin <pablo.polvorin@process-one.net>2010-12-02 12:55:06 -0300
commitc890b17834f2593a9af56e093523653102349989 (patch)
tree22534b0d83bf9d162f3f73994fa8a764171d4d67 /src
parentfix pubsub cross domain eventing (EJAB-1340) (diff)
Fix cyrsasl_digest RFC-2831 2.1.2.1 (EJAB-476)
Fix sasl digest bug when username|password|resource strings had all characters <= U+00FF and at least one character >= U+0080. Warnning: Note that by fixing the bug, we may be broking compatibility with clients that "implements" it. See comments on https://support.process-one.net/browse/EJAB-476
Diffstat (limited to 'src')
-rw-r--r--src/cyrsasl_digest.erl85
1 files changed, 83 insertions, 2 deletions
diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
index 2a7ce2a69..2416cd06f 100644
--- a/src/cyrsasl_digest.erl
+++ b/src/cyrsasl_digest.erl
@@ -191,14 +191,20 @@ response(KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) ->
DigestURI = xml:get_attr_s("digest-uri", KeyVals),
NC = xml:get_attr_s("nc", KeyVals),
QOP = xml:get_attr_s("qop", KeyVals),
+
+ %% handle non-fully latin-1 strings as specified
+ %% on RFC 2831 Section 2.1.2.1 (EJAB-476)
+ SUser = sanitize(User),
+ SPasswd = sanitize(Passwd),
+ SRealm = sanitize(Realm),
A1 = case AuthzId of
"" ->
binary_to_list(
- crypto:md5(User ++ ":" ++ Realm ++ ":" ++ Passwd)) ++
+ crypto:md5(SUser ++ ":" ++ SRealm ++ ":" ++ SPasswd)) ++
":" ++ Nonce ++ ":" ++ CNonce;
_ ->
binary_to_list(
- crypto:md5(User ++ ":" ++ Realm ++ ":" ++ Passwd)) ++
+ crypto:md5(SUser ++ ":" ++ SRealm ++ ":" ++ SPasswd)) ++
":" ++ Nonce ++ ":" ++ CNonce ++ ":" ++ AuthzId
end,
A2 = case QOP of
@@ -214,4 +220,79 @@ response(KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) ->
hex(binary_to_list(crypto:md5(T))).
+sanitize(V) ->
+ L = from_utf8(V),
+ case lists:all(fun is_latin1/1, L) of
+ true -> L;
+ false -> V
+ end.
+
+%%%% copied from xmerl_ucs:from_utf8/1 and xmerl_ucs:is_latin1/1 , to not
+%%%% require xmerl as a dependency only for this.
+
+from_utf8(Bin) when is_binary(Bin) -> from_utf8(binary_to_list(Bin));
+from_utf8(List) ->
+ case expand_utf8(List) of
+ {Result,0} -> Result;
+ {_Res,_NumBadChar} ->
+ exit({ucs,{bad_utf8_character_code}})
+ end.
+
+
+
+%% expand_utf8([Byte]) -> {[UnicodeChar],NumberOfBadBytes}
+%% Expand UTF8 byte sequences to ISO 10646/Unicode
+%% charactes. Any illegal bytes are removed and the number of
+%% bad bytes are returned.
+%%
+%% Reference:
+%% RFC 3629: "UTF-8, a transformation format of ISO 10646".
+
+expand_utf8(Str) ->
+ expand_utf8_1(Str, [], 0).
+
+expand_utf8_1([C|Cs], Acc, Bad) when C < 16#80 ->
+ %% Plain Ascii character.
+ expand_utf8_1(Cs, [C|Acc], Bad);
+expand_utf8_1([C1,C2|Cs], Acc, Bad) when C1 band 16#E0 =:= 16#C0,
+ C2 band 16#C0 =:= 16#80 ->
+ case ((C1 band 16#1F) bsl 6) bor (C2 band 16#3F) of
+ C when 16#80 =< C ->
+ expand_utf8_1(Cs, [C|Acc], Bad);
+ _ ->
+ %% Bad range.
+ expand_utf8_1(Cs, Acc, Bad+1)
+ end;
+expand_utf8_1([C1,C2,C3|Cs], Acc, Bad) when C1 band 16#F0 =:= 16#E0,
+ C2 band 16#C0 =:= 16#80,
+ C3 band 16#C0 =:= 16#80 ->
+ case ((((C1 band 16#0F) bsl 6) bor (C2 band 16#3F)) bsl 6) bor
+ (C3 band 16#3F) of
+ C when 16#800 =< C ->
+ expand_utf8_1(Cs, [C|Acc], Bad);
+ _ ->
+ %% Bad range.
+ expand_utf8_1(Cs, Acc, Bad+1)
+ end;
+expand_utf8_1([C1,C2,C3,C4|Cs], Acc, Bad) when C1 band 16#F8 =:= 16#F0,
+ C2 band 16#C0 =:= 16#80,
+ C3 band 16#C0 =:= 16#80,
+ C4 band 16#C0 =:= 16#80 ->
+ case ((((((C1 band 16#0F) bsl 6) bor (C2 band 16#3F)) bsl 6) bor
+ (C3 band 16#3F)) bsl 6) bor (C4 band 16#3F) of
+ C when 16#10000 =< C ->
+ expand_utf8_1(Cs, [C|Acc], Bad);
+ _ ->
+ %% Bad range.
+ expand_utf8_1(Cs, Acc, Bad+1)
+ end;
+expand_utf8_1([_|Cs], Acc, Bad) ->
+ %% Ignore bad character.
+ expand_utf8_1(Cs, Acc, Bad+1);
+expand_utf8_1([], Acc, Bad) -> {lists:reverse(Acc),Bad}.
+
+
+%%% Test for legitimate Latin-1 code
+is_latin1(Ch) when is_integer(Ch), Ch >= 0, Ch =< 255 -> true;
+is_latin1(_) -> false.