ttcn3-asterisk: Validate Asterisk generates correct AKAv1-MD5 digest response
Values taken from pcap "register-unregister-example.pcapng" in SYS#6960
against testing Kamailio as IMS Core.
Related: SYS#6960
Change-Id: I0c6a6ff86a8b32383f17487dc9eb46d0bf2bf7c2
diff --git a/library/SIP_Templates.ttcn b/library/SIP_Templates.ttcn
index f251767..77d4ee0 100644
--- a/library/SIP_Templates.ttcn
+++ b/library/SIP_Templates.ttcn
@@ -1275,7 +1275,17 @@
f_sip_str_unquote(realm) & ":" &
password;
var charstring digestA1 := f_str_tolower(f_calculateMD5(A1));
- log("A1: md5('", A1, "') = ", digestA1);
+ log("A1: md5(", A1, ") = ", digestA1);
+ return digestA1;
+}
+
+/* RFC 3310: Same as f_sip_digest_A1(), but using an octet buffer as password (AKAv1-MD5, pwd=RES) */
+function f_sip_digest_A1_octpwd(charstring user, charstring realm, octetstring password) return charstring {
+ var charstring A1pre := f_sip_str_unquote(user) & ":" &
+ f_sip_str_unquote(realm) & ":";
+ var octetstring A1 := char2oct(A1pre) & password;
+ var charstring digestA1 := f_str_tolower(oct2str(f_calculateMD5_oct(A1)));
+ log("A1-octpwd: md5(", A1, ") = ", digestA1);
return digestA1;
}
@@ -1284,7 +1294,7 @@
var charstring A2 := method & ":" & uri
var charstring digestA2 := f_str_tolower(f_calculateMD5(A2));
- log("A2: md5('", A2, "') = ", digestA2);
+ log("A2: md5(", A2, ") = ", digestA2);
return digestA2;
}
@@ -1298,7 +1308,7 @@
f_sip_str_unquote(qop) & ":" &
digestA2;
var charstring req_digest := f_sip_digest_KD(digestA1, digest_data);
- log("Request-Digest: md5('", digestA1, ":", digest_data ,"') = ", req_digest);
+ log("Request-Digest: md5(\"" & digestA1 & ":" & digest_data & "\") = " & "\"" & req_digest & "\"");
return req_digest;
}
@@ -1310,7 +1320,41 @@
}
/* Digest Auth: RFC 2617 */
-function f_sip_digest_gen_Authorization(WwwAuthenticate www_authenticate,
+function f_sip_digest_gen_Authorization_Response_MD5(charstring user, charstring realm, charstring password,
+ charstring method, charstring uri, charstring qop,
+ charstring nonce, charstring cnonce, charstring nc)
+return charstring {
+ /* RFC 2617 3.2.2.2 A1 */
+ var charstring digestA1 := f_sip_digest_A1(user, realm, password);
+
+ /* RFC 2617 3.2.2.3 A2 */
+ var charstring digestA2 := f_sip_digest_A2(method, uri);
+
+ /* RFC 2617 3.2.2.1 Request-Digest */
+ var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
+ nc, cnonce,
+ qop, digestA2);
+ return req_digest;
+}
+
+/* Digest Auth: RFC 2617 */
+function f_sip_digest_gen_Authorization_Response_AKAv1MD5(charstring user, charstring realm, octetstring password,
+ charstring method, charstring uri, charstring qop,
+ charstring nonce, charstring cnonce, charstring nc)
+return charstring {
+ /* RFC 2617 3.2.2.2 A1 */
+ var charstring digestA1 := f_sip_digest_A1_octpwd(user, realm, password);
+ /* RFC 2617 3.2.2.3 A2 */
+ var charstring digestA2 := f_sip_digest_A2(method, uri);
+
+ /* RFC 2617 3.2.2.1 Request-Digest */
+ var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
+ nc, cnonce,
+ qop, digestA2);
+ return req_digest;
+}
+
+function f_sip_digest_gen_Authorization_MD5(WwwAuthenticate www_authenticate,
charstring user, charstring password,
charstring method, charstring uri,
charstring cnonce := "0a4f113b", integer nc_int := 1) return Authorization {
@@ -1343,17 +1387,13 @@
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected qop: ", qop));
}
var charstring selected_qop := "auth";
-
- /* RFC 2617 3.2.2.2 A1 */
- var charstring digestA1 := f_sip_digest_A1(user, realm, password);
- /* RFC 2617 3.2.2.3 A2 */
- var charstring digestA2 := f_sip_digest_A2(method, uri);
-
- /* RFC 2617 3.2.2.1 Request-Digest */
var charstring nc := f_str_tolower(hex2str(int2hex(nc_int, 8)));
- var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
- nc, cnonce,
- selected_qop, digestA2);
+
+ var charstring req_digest;
+ req_digest :=
+ f_sip_digest_gen_Authorization_Response_MD5(user, realm, password,
+ method, uri, selected_qop,
+ nonce, cnonce, nc);
cred := ts_Credentials_DigestResponseMD5(user, realm, nonce,
uri, req_digest,
@@ -1363,6 +1403,55 @@
return valueof(authorization);
}
+/* RFC 3310: Same as f_sip_digest_validate_Authorization_MD5(), but using an octet buffer as password (AKAv1-MD5, pwd=RES) */
+function f_sip_digest_validate_Authorization_AKAv1MD5(Authorization authorization, charstring method, octetstring password) {
+ var CommaParam_List auth_pars := authorization.body.digestResponse;
+ var template (omit) GenericParam rx_param;
+
+ rx_param := f_sip_param_find(auth_pars, "algorithm");
+ if (istemplatekind(rx_param, "omit")) {
+ /* Assume MD5 if not set */
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Algorithm param not present");
+ } else {
+ var charstring algorithm := valueof(rx_param.paramValue);
+ if (f_strstr(algorithm, "AKAv1-MD5") == -1) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Unexpected algorithm: ", algorithm));
+ }
+ }
+
+ var charstring user := f_sip_param_get_value_present_or_fail(auth_pars, "username");
+ var charstring realm := f_sip_param_get_value_present_or_fail(auth_pars, "realm");
+ var charstring uri := f_sip_param_get_value_present_or_fail(auth_pars, "uri");
+ var charstring nonce := f_sip_param_get_value_present_or_fail(auth_pars, "nonce");
+ var charstring qop := f_sip_param_get_value_present_or_fail(auth_pars, "qop");
+ var charstring response := f_sip_param_get_value_present_or_fail(auth_pars, "response");
+ var charstring cnonce := f_sip_param_get_value_present_or_fail(auth_pars, "cnonce");
+ var charstring nc := f_sip_param_get_value_present_or_fail(auth_pars, "nc");
+
+ if (f_strstr(qop, "auth") == -1) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected qop: ", qop));
+ }
+
+ var charstring exp_response :=
+ f_sip_digest_gen_Authorization_Response_AKAv1MD5(f_sip_str_unquote(user),
+ f_sip_str_unquote(realm),
+ password,
+ method,
+ f_sip_str_unquote(uri),
+ qop,
+ f_sip_str_unquote(nonce),
+ f_sip_str_unquote(cnonce),
+ nc);
+
+ response := f_sip_str_unquote(response);
+ if (response != exp_response) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Wrong digest response: ", response,
+ " vs exp: ", exp_response, ". Params: ", auth_pars));
+ }
+}
+
/* RFC 2617 3.5 Example */
function f_sip_digest_selftest() {
/*
@@ -1400,13 +1489,13 @@
ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
var Authorization authorization :=
- f_sip_digest_gen_Authorization(valueof(www_authenticate),
- "Mufasa",
- "Circle Of Life",
- "GET",
- "/dir/index.html",
- cnonce := "0a4f113b",
- nc_int := 1);
+ f_sip_digest_gen_Authorization_MD5(valueof(www_authenticate),
+ "Mufasa",
+ "Circle Of Life",
+ "GET",
+ "/dir/index.html",
+ cnonce := "0a4f113b",
+ nc_int := 1);
var CommaParam_List digestResp := authorization.body.digestResponse;
f_sip_param_match_value_or_fail(digestResp, "realm", f_sip_str_quote("testrealm@host.com"));