pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/37065?usp=email )
Change subject: ttcn3-asterisk: Validate Asterisk generates correct AKAv1-MD5 digest
response
......................................................................
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
---
M asterisk/Asterisk_Tests.ttcn
M asterisk/IMS_ConnectionHandler.ttcn
M asterisk/SIP_ConnectionHandler.ttcn
M library/SIP_Templates.ttcn
4 files changed, 163 insertions(+), 53 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/65/37065/1
diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn
index ba7cb38..a96e66a 100644
--- a/asterisk/Asterisk_Tests.ttcn
+++ b/asterisk/Asterisk_Tests.ttcn
@@ -66,13 +66,6 @@
const charstring broadcast_sip_extension := "0500";
-/* TODO: need to find correct RES, CK, IK, values for:
- * Response: "a19de225d030e6e0ec20f6de5f9dd80d"
- * CNonce Value: "9a6460bcc3c84a3eac69455a93b67a77"
- */
-const charstring c_auth_res := "a19de225d030e6e0";
-const charstring c_auth_ck := "9a6460bcc3c84a3eac69455a93b67a77";
-const charstring c_auth_ik := "5238297dfcca759bd05d48ff49bc63fa";
function f_init_ConnHdlrPars(integer idx := 1) runs on test_CT return SIPConnHdlrPars {
var template (value) CallPars cp := t_CallPars(mp_local_sip_host, 1234 + 2*idx);
@@ -384,15 +377,17 @@
/* Trigger registration: */
f_ami_action_PJSIPRegister(AMI_CLIENT, mp_volte_ims_outbound_registration);
- var charstring rand_str := oct2str(pars.subscr.rand);
- var charstring autn_str := oct2str(pars.subscr.autn);
+ var charstring rand_str := oct2str(pars.subscr.auth.rand);
+ var charstring autn_str := oct2str(pars.subscr.auth.autn);
AMI_CLIENT.receive(tr_AMI_Event_AuthRequest(mp_volte_ims_outbound_registration,
rand := pattern @nocase rand_str,
autn := pattern @nocase autn_str));
f_ami_action_AuthResponse_RES(AMI_CLIENT,
mp_volte_ims_outbound_registration,
- c_auth_res, c_auth_ck, c_auth_ik);
+ f_str_tolower(oct2str(pars.subscr.auth.res)),
+ f_str_tolower(oct2str(pars.subscr.auth.ck)),
+ f_str_tolower(oct2str(pars.subscr.auth.ik)));
AMI_CLIENT.receive(tr_AMI_Event_Registry(f_sip_SipAddr_to_str(pars.subscr.local_sip_record),
"sip:" & mp_ims_domain,
diff --git a/asterisk/IMS_ConnectionHandler.ttcn b/asterisk/IMS_ConnectionHandler.ttcn
index 9a37b05..f10e2aa 100644
--- a/asterisk/IMS_ConnectionHandler.ttcn
+++ b/asterisk/IMS_ConnectionHandler.ttcn
@@ -56,6 +56,14 @@
}
type record of IMS_ConnHdlr IMS_ConnHdlrList;
+type record IMS_AuthVector {
+ OCT16 rand,
+ OCT16 autn,
+ OCT8 res,
+ OCT16 ck,
+ OCT16 ik
+}
+
type record IMS_ConnHdlrSubscrPars {
charstring remote_sip_host optional,
uint16_t remote_sip_port optional,
@@ -65,8 +73,7 @@
charstring msisdn,
/* Expected User-Location-Info in P-Access-Network-Info */
charstring uli_str,
- octetstring rand,
- octetstring autn,
+ IMS_AuthVector auth,
charstring ipsec_auth_key,
integer ipsec_local_spi_c,
integer ipsec_local_spi_s,
@@ -158,10 +165,15 @@
password := password,
msisdn := msisdn,
uli_str := "2380100010000101",
- /* The Nonce field is the Base64 encoded version of the RAND value and concatenated with
the AUTN: */
- rand := '14987631f65f8e3788a0798b6ebcd08e'O,
- autn := 'f6e19a7ccb028000a06b19c9544516e5'O,
- ipsec_auth_key := "0x5238297dfcca759bd05d48ff49bc63fa00000000",
+ auth := {
+ /* The Nonce field is the Base64 encoded version of the RAND value and concatenated
with the AUTN: */
+ rand := 'd5d5de2bce418d7865ed7fa6956618a2'O,
+ autn := 'd42e61db5f15800067393a5b7691a227'O,
+ res := '6f2556bbe4366ab1'O,
+ ck := '0b389d08c833991734936bec55cac800'O,
+ ik := '17141862125bd30c81c4224391a0909a'O
+ },
+ ipsec_auth_key := "0x17141862125bd30c81c4224391a0909a00000000",
ipsec_local_spi_c := 4142,
ipsec_local_spi_s := 4143,
ipsec_remote_spi_c := omit,
@@ -250,8 +262,7 @@
/* HTTP Digest Authentication Using AKA (AKAv1-MD5): RFC 3310 */
function f_tr_Authorization_AKAv1MD5(WwwAuthenticate www_authenticate,
charstring username,
- charstring uri,
- integer nc_int := 1)
+ charstring uri)
return template (present) Authorization {
var CommaParam_List digestCln;
var template (present) Authorization authorization;
@@ -280,6 +291,12 @@
return authorization;
}
+private function f_ims_validate_Authorization_AKAv1MD5_Response(Authorization
authorization, charstring method)
+runs on IMS_ConnHdlr {
+ f_sip_digest_validate_Authorization_AKAv1MD5(authorization, method,
g_pars.subscr.auth.res);
+}
+
+
private function f_ims_validate_register_contact(Contact rx_contact)
{
/* IMS contact shows up like this:
@@ -532,7 +549,8 @@
ts_Param("realm", f_sip_str_quote(g_pars.realm)),
ts_Param("qop", f_sip_str_quote("auth")),
ts_Param("algorithm", "AKAv1-MD5"),
- ts_Param("nonce", f_sip_str_quote(f_nonce_from_rand_autn(g_pars.subscr.rand,
g_pars.subscr.autn)))
+ ts_Param("nonce",
f_sip_str_quote(f_nonce_from_rand_autn(g_pars.subscr.auth.rand,
+ g_pars.subscr.auth.autn)))
/* "opaque not needed in IMS "*/
};
wwwAuthenticate := ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
@@ -569,17 +587,9 @@
SIP.send(tx_resp);
/* Now we should receive a new REGISTER over ipsec: */
-
- /* TODO: Generate expected Authoritzation based on AKAv1-MD5: */
- /*authorization := f_sip_digest_gen_Authorization(valueof(wwwAuthenticate),
- g_pars.user, g_pars.subscr.password,
- "REGISTER",
- f_sip_SipUrl_to_str(g_pars.subscr.registrar_sip_record.addr.nameAddr.addrSpec))
- */
authorization := f_tr_Authorization_AKAv1MD5(valueof(wwwAuthenticate),
g_pars.subscr.imsi & "@" & g_pars.realm,
f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri));
- /* TODO: match Authorization from above: */
exp_req :=
tr_SIP_REGISTER(g_pars.registrar_sip_req_uri,
?,
@@ -607,6 +617,9 @@
userAgent := omit);
SIP.send(tx_resp);
+ /* Validate Digest Response: */
+ f_ims_validate_Authorization_AKAv1MD5_Response(g_rx_sip_req.msgHeader.authorization,
"REGISTER");
+
/* Validate P-Access-Network-Info: */
f_ims_validate_register_P_Access_Network_info(g_rx_sip_req, exp_present := true);
diff --git a/asterisk/SIP_ConnectionHandler.ttcn b/asterisk/SIP_ConnectionHandler.ttcn
index a14dd03..cd50be6 100644
--- a/asterisk/SIP_ConnectionHandler.ttcn
+++ b/asterisk/SIP_ConnectionHandler.ttcn
@@ -296,10 +296,10 @@
as_SIP_expect_resp(exp);
/* Digest Auth: RFC 2617 */
- authorization :=
f_sip_digest_gen_Authorization(g_rx_sip_resp.msgHeader.wwwAuthenticate,
- g_pars.user, g_pars.password,
- "REGISTER",
- f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
+ authorization :=
f_sip_digest_gen_Authorization_MD5(g_rx_sip_resp.msgHeader.wwwAuthenticate,
+ g_pars.user, g_pars.password,
+ "REGISTER",
+ f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
/* New transaction: */
g_pars.registrar_sip_seq_nr := g_pars.registrar_sip_seq_nr + 1;
@@ -381,7 +381,7 @@
as_SIP_expect_resp(exp);
/* Digest Auth: RFC 2617 */
- req.msgHeader.authorization := f_sip_digest_gen_Authorization(
+ req.msgHeader.authorization := f_sip_digest_gen_Authorization_MD5(
g_rx_sip_resp.msgHeader.wwwAuthenticate,
g_pars.user, g_pars.password,
"INVITE",
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(a)host.com"))om"));
--
To view, visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/37065?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I0c6a6ff86a8b32383f17487dc9eb46d0bf2bf7c2
Gerrit-Change-Number: 37065
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: newchange