ItsPkiItss_TestCases.ttcn 452 KB
Newer Older
                                                                                                                                                                                                                       )
                                                                                                                                                                                           )
                                                                                                                                                                )
                                                                                                                                )
                                                                                                                  ),
                                                                                       mw_geoNwShbPacket
                                                                                       ))) {
        }
      } // End of altstep a_await_cam_with_current_cert

    } // End of group itss_helpers

    // ETSI TS 103 525-2 V2.0.2 (2023-07) Clause 5.2.2.1  Enrollment request
    group itss_enrolment_request {

      /**
       * @desc Check that IUT sends an enrolment request when triggered.
       * <pre>
       * Pics Selection: PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT
       * Initial conditions: 
       *     with {
       *         the IUT being in the "initial state"
       *     }
       * Expected behaviour:
       *     ensure that {
       *         when {
       *             the IUT is triggered to requested a new Enrolment Certificate (EC)
       *         }
       *         then {
       *             the IUT sends to EA an EnrolmentRequestMessage
       *         }
       *     }
       * </pre>
       * 
       * @see       ETSI TS 103 525-2 v2.0.1 SECPKI_ITSS_ENR_01_BV
       * @reference ETSI TS 102 941 [2], clause 6.1.3
       */
      testcase TC_SECPKI_ITSS_ENR_01_BV() runs on ItsMtc system ItsPkiItssSystem {
        // Local variables
        var ItsPkiItss v_itss;
        var ItsPkiHttp v_ea;

        // Test control
        if (not PICS_IUT_ITS_S_ROLE or not PICS_SECPKI_ENROLMENT) {
          log("*** " & testcasename() & ": PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT required for executing the TC ***");
          setverdict(inconc);
          stop;
        }

        // Test component configuration
        f_cfMtcUp01(v_itss, v_ea);

        // Start components
        v_itss.start(f_TC_SECPKI_ITSS_ENR_01_BV_itss());
        v_ea.start(f_TC_SECPKI_ITSS_ENR_01_BV_pki());

        // Synchronization
        f_serverSync2ClientsAndStop({c_prDone, c_tbDone});

        // Cleanup
        f_cfMtcDown01(v_itss, v_ea);

      } // End of testcase TC_SECPKI_ITSS_ENR_01_BV

      group f_TC_SECPKI_ITSS_ENR_01_BV {

        function f_TC_SECPKI_ITSS_ENR_01_BV_itss() runs on ItsPkiItss system ItsPkiItssSystem {
          // Local variables
          var HashedId8               v_certificate_digest;
          var EtsiTs103097Certificate v_certificate;

          // Test component configuration
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398

          // Test adapter configuration

          // Preamble
          // Initial state: No CAM shall be emitted
          geoNetworkingPort.clear;
          tc_noac.start;
          alt {
            [] geoNetworkingPort.receive {
              log("*** " & testcasename() & "itss: FAIL: Unexpected GeoNet message received ***");
              f_selfOrClientSyncAndVerdict(c_prDone, e_error);
            }
            [] tc_noac.timeout {
              log("*** " & testcasename() & "itss: INFO: No GeoNet message received. Continue ***");
              f_selfOrClientSyncAndVerdict(c_prDone, e_success);
              }
          } // End of 'alt' statement

          // Test Body
          f_sendUtTriggerEnrolmentRequestPrimitive();
          tc_ac.start; // TDOD To refined, use altstep
          alt {
            [] utPort.receive(UtPkiTriggerInd: { state := 1 }) {
              tc_ac.stop;
              log("*** " & testcasename() & "itss: INFO: IUT is in enrolment state ***");
            }
            [] tc_ac.timeout {
              log("*** " & testcasename() & "itss: DBG: IUT state update not recieved. Assuming it was OK... ***");
              //f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
            }
          } // End of 'alt' statement
          tc_noac.start;
          alt {
            [] geoNetworkingPort.receive {
              log("*** " & testcasename() & "itss: FAIL: Unexpected GeoNet message received ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
            }
            [] tc_noac.timeout {
              log("*** " & testcasename() & "itss: PASS: Enrolment trigger sent succesfully ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
            }
          } // End of 'alt' statement

          // Postamble
          f_cfDown_itss();
        } // End of function f_TC_SECPKI_ITSS_ENR_01_BV_itss

        function f_TC_SECPKI_ITSS_ENR_01_BV_pki() runs on ItsPkiHttp system ItsPkiItssSystem {
          // Local variable
          var Headers v_headers;
          var HttpMessage v_request;

          // Test component configuration
          f_cfHttpUp(PICS_TS_EA_CERTIFICATE_ID, PICS_TS_AA_CERTIFICATE_ID);

          // Test adapter configuration

          // Preamble
          f_init_default_headers_list(-, "inner_ec_response", v_headers);
          f_selfOrClientSyncAndVerdict(c_prDone, e_success);

          // Test Body
          tc_ac.start;
          alt {
            [] a_await_ec_http_request_from_iut(mw_http_ec_request_generic, v_request) {
              var Oct16 v_request_hash;
              var Oct16 v_aes_enc_key;
              var Ieee1609Dot2Data v_outer_encrypted_message;
              var Ieee1609Dot2Data v_decrypted_message;
              var InnerEcRequest v_inner_ec_request;
              var InnerEcResponse v_inner_ec_response;
              var Ieee1609Dot2Data v_response_message;
              var EtsiTs102941Data v_pki_request;

              tc_ac.stop;

              if (not(f_read_ec_request_from_iut_itss(v_request.request.body.binary_body.ieee1609dot2_data,
                                                      v_request_hash, v_aes_enc_key,
                                                      v_decrypted_message,
                                                      v_pki_request,
                                                      v_inner_ec_request))) {
                f_send_500_Internal_Error(v_headers);
                log("*** " & testcasename() & ": INCONC: Canonical key is not set properly ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout); // to emulate inconc
              } else {
                f_send_500_Internal_Error(v_headers); // we dont care about response
                // Set verdict
                log("*** " & testcasename() & ": PASS: InnerEcRequest received ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
              }
            }
            [] tc_ac.timeout {
              log("*** " & testcasename() & ": INCONC: Expected message not received ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
            }
          } // End of 'alt' statement

          // Postamble
          f_cfHttpDown();
        } // End of function f_TC_SECPKI_ITSS_ENR_01_BV_pki

      } // End of group f_TC_SECPKI_ITSS_ENR_01_BV

      /**
       * @desc If the enrolment request of the IUT is an initial enrolment request, the itsId 
       *       (contained in the InnerECRequest) shall be set to the canonical identifier, the 
       *       signer (contained in the outer EtsiTs1030971Data-Signed) shall be set to self and 
       *       the outer signature shall be computed using the canonical private key.
       * <pre>
       * Pics Selection: PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT
       * Expected behaviour:
       *     ensure that {
       *         when {
       *             the IUT is requested to send an EnrolmentRequestMessage
       *         }
       *         then {
       *             the IUT sends an EtsiTs103097Data-Encrypted
       *                 containing an encrypted EtsiTs103097Data-Signed
       *                     containing EtsiTs103097Data
       *                          containing InnerECRequestSignedForPOP
       *                             containing InnerEcRequest
       *                                 containing itsId
       *                                     indicating the canonical identifier of the ITS-S 
       *                 and containing signer
       *                     declared as self
       *                 and containing signature 
       *                     computed using the canonical private key
       *         }
       *     }
       * </pre>
       * 
       * @see       ETSI TS 103 525-2 v1.2.1 SECPKI_ITSS_ENR_02_BV
       * @reference ETSI TS 102 941, clause 6.1.3
       */
      testcase TC_SECPKI_ITSS_ENR_02_BV() runs on ItsMtc system ItsPkiItssSystem {
        // Local variables
        var ItsPkiItss v_itss;
        var ItsPkiHttp v_ea;

        // Test control
        if (not PICS_IUT_ITS_S_ROLE or not PICS_SECPKI_ENROLMENT) {
          log("*** " & testcasename() & ": PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT required for executing the TC ***");
          setverdict(inconc);
          stop;
        }

        // Test component configuration
        f_cfMtcUp01(v_itss, v_ea);

        // Start components
        v_itss.start(f_TC_SECPKI_ITSS_ENR_01_BV_itss());
        v_ea.start(f_TC_SECPKI_ITSS_ENR_02_BV_pki());

        // Synchronization
        f_serverSync2ClientsAndStop({c_prDone, c_tbDone});

        // Cleanup
        f_cfMtcDown01(v_itss, v_ea);

      } // End of testcase TC_SECPKI_ITSS_ENR_02_BV

      group f_TC_SECPKI_ITSS_ENR_02_BV {
        function f_TC_SECPKI_ITSS_ENR_02_BV_pki() runs on ItsPkiHttp system ItsPkiItssSystem {
          // Local variable
          var Headers v_headers;
          var HttpMessage v_request;
          
          // Test component configuration
          f_cfHttpUp(PICS_TS_EA_CERTIFICATE_ID, PICS_TS_AA_CERTIFICATE_ID);
          
          // Test adapter configuration
          
          // Preamble
          f_init_default_headers_list(-, "inner_ec_response", v_headers);
          f_selfOrClientSyncAndVerdict(c_prDone, e_success);
          
          // Test Body
          tc_ac.start;
          alt {
            [] a_await_ec_http_request_from_iut(mw_http_ec_request_generic, v_request)
            {
              var Ieee1609Dot2Data v_decrypted_message;
              var InnerEcRequest   v_inner_ec_request;
              var InnerEcResponse  v_inner_ec_response;
              var Ieee1609Dot2Data v_response_message;
              var EtsiTs102941Data v_pki_request;
              var Oct16 v_request_hash, v_aes_enc_key;
              var PublicVerificationKey v_canonical_key;
              tc_ac.stop;

              if( not f_read_ec_request_from_iut_itss(v_request.request.body.binary_body.ieee1609dot2_data,
                                                      v_request_hash, v_aes_enc_key,
                                                      v_decrypted_message,
                                                      v_pki_request,
                                                      v_inner_ec_request))
              {
                log("*** " & testcasename() & ": FAIL: Can't parse enrolment request***");
                f_send_500_Internal_Error(v_headers);
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }

              if(not f_http_build_error_ec_response(unknownits, v_request_hash, vc_eaPrivateKey,
                                                    vc_eaWholeHash, v_aes_enc_key, v_response_message))
              {
                log("*** " & testcasename() & ": INCOMC: Can't generate enrolment response***");
                f_send_500_Internal_Error(v_headers);
                f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
              }
              f_http_send( v_headers, m_http_response( m_http_response_ok( m_http_message_body_binary( m_binary_body_ieee1609dot2_data( v_response_message)),
                                                                           v_headers)));
              if( not isvalue(v_inner_ec_request) ){
                log("*** " & testcasename() & ": FAIL: Can't parse enrolment request***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }

              if(not match(v_inner_ec_request.itsId, LibItsPki_Pics.PICS_ITS_S_CANONICAL_ID)){
                log("*** " & testcasename() & ": FAIL: Canonical ID mismatched ***");
                log("*** " & testcasename() & ": FAIL:     ", match(v_inner_ec_request.itsId, LibItsPki_Pics.PICS_ITS_S_CANONICAL_ID));
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }
              if (not ischosen(v_decrypted_message.content.signedData)) {
                log("*** " & testcasename() & ": FAIL: EC request shall contain signed message ***");
                log("*** " & testcasename() & ": FAIL:     inner data content=", v_decrypted_message.content);
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }
              if (not ischosen(v_decrypted_message.content.signedData.signer.self_)) {
                log("*** " & testcasename() & ": FAIL: EC request shall be self-signed by cannonical key ***");
                log("*** " & testcasename() & ": FAIL:     signerInfo=", v_decrypted_message.content.signedData.signer);
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }

              if (not f_get_canonical_itss_key(v_canonical_key)){
                log("*** " & testcasename() & ": INCONC: Unknown ITS-S canonical public key ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout); // emulate inconc
              }
              
              if (not(f_verifyEcdsa(bit2oct(encvalue(v_decrypted_message.content.signedData.tbsData)),
                                    int2oct(0, 32), // issuer is emtpy string 
                                    v_decrypted_message.content.signedData.signature_,
                                    v_canonical_key))){
                log("*** " & testcasename() & ": FAIL: EC request signature verification failed ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }

              // Set verdict
              log("*** " & testcasename() & ": PASS: InnerEcRequest received ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
            }
            [] tc_ac.timeout {
              log("*** " & testcasename() & ": INCONC: Expected message not received ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
            }
          } // End of 'alt' statement
          
          // Postamble
          f_cfHttpDown();
        } // End of function f_TC_SECPKI_ITSS_ENR_01_BV_pki

      } // End of group f_TC_SECPKI_ITSS_ENR_02_BV

      /**
       * @desc In presence of a valid EC, the enrolment request of the IUT is a rekeying enrolment 
       *       request with the itsId (contained in the InnerECRequest) and the SignerIdentifier 
       *       (contained in the outer EtsiTs1030971Data-Signed) both declared as digest containing 
       *       the HashedId8 of the EC and the outer signature computed using the current valid EC 
       *       private key corresponding to the verification public key.
       * <pre>
       * Pics Selection: PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT and PICS_SECPKI_REENROLMENT
       * Expected behaviour:
       *     ensure that {
       *         when {
       *             the IUT is requested to send an EnrolmentRequestMessage
       *         }
       *         then {
       *             the IUT sends an EtsiTs103097Data-Encrypted
       *                 containing an encrypted EtsiTs103097Data-Signed
       *                     containing EtsiTs103097Data
       *                          containing InnerECRequestSignedForPOP
       *                             containing InnerEcRequest
       *                                 containing itsId
       *                                     declared as digest containing the HashedId8 of the EC identifier
       *                 and containing signer
       *                     declared as digest containing the HashedId8 of the EC identifier 
       *                 and containing signature 
       *                     computed using the current valid EC private key corresponding to the verification public key
       *         }
       *     }
       * </pre>
       * 
       * @see       ETSI TS 103 525-2 v1.2.1 SECPKI_ITSS_ENR_03_BV
       * @reference ETSI TS 102 941, clause 6.1.3
       */
      testcase TC_SECPKI_ITSS_ENR_03_BV() runs on ItsMtc system ItsPkiItssSystem {
        // Local variables
        var ItsPkiItss v_itss;
        var ItsPkiHttp v_ea;

        // Test control
        if (not PICS_IUT_ITS_S_ROLE or not PICS_SECPKI_ENROLMENT or not PICS_SECPKI_REENROLMENT) {
          log("*** " & testcasename() & ": PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT and PICS_SECPKI_REENROLMENT required for executing the TC ***");
          setverdict(inconc);
          stop;
        }

        // Test component configuration
        f_cfMtcUp01(v_itss, v_ea);

        // Start components
        v_itss.start(f_TC_SECPKI_ITSS_ENR_03_BV_itss());
        v_ea.start(f_TC_SECPKI_ITSS_ENR_03_BV_pki());

        // Synchronization
        f_serverSync2ClientsAndStop({c_prDone, c_tbDone});

        // Cleanup
        f_cfMtcDown01(v_itss, v_ea);

      } // End of testcase TC_SECPKI_ITSS_ENR_03_BV

      group f_TC_SECPKI_ITSS_ENR_03_BV {

        function f_TC_SECPKI_ITSS_ENR_03_BV_itss(
                                                 in float p_delay := 0.0
        ) runs on ItsPkiItss system ItsPkiItssSystem {
          // Test component configuration

          // Test adapter configuration

          // Preamble
          // Initial state: No CAM shall be emitted
          geoNetworkingPort.clear;
          tc_noac.start;
          alt {
            [] geoNetworkingPort.receive {
              log("*** " & testcasename() & "_itss: ERROR: Unexpected GeoNet message received ***");
              f_selfOrClientSyncAndVerdict(c_prDone, e_error);
              }
            [] tc_noac.timeout {
              // Trigger the first enrolment
              log("*** " & testcasename() & "_itss: INFO: No GeoNet message received. Continue ***");
              f_sendUtTriggerEnrolmentRequestPrimitive();
              f_selfOrClientSyncAndVerdict(c_prDone, e_success);
              } 
            } // End of 'alt' statement

          // Test Body
          // Give time to the IUT to setup enrol state
          tc_ac.start; // TDOD To refined, use altstep
          alt {
            [] utPort.receive(UtPkiTriggerInd: { state := 1 }) {
              tc_ac.stop;
              log("*** " & testcasename() & "_itss: INFO: IUT is in enrolment state ***");
            }
            [] tc_ac.timeout {
              log("*** " & testcasename() & "_itss: DBG: IUT state update not recieved. Assuming it was OK... ***");
              //f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
            }
          } // End of 'alt' statement

          if(p_delay > 0.0){
            log("*** " & testcasename() & "_itss: INFO: Wait for second enrolment trigger ***");
            f_sleep(p_delay);
          }

          // Trigger the second enrolment
          f_sendUtTriggerEnrolmentRequestPrimitive();

          log("*** " & testcasename() & "_itss: PASS: Re-enrolment trigger sent succesfully ***");
          f_selfOrClientSyncAndVerdict(c_tbDone, e_success);

          // Postamble
          f_cfDown_itss();
        } // End of function f_TC_SECPKI_ITSS_ENR_03_BV_itss

        function f_TC_SECPKI_ITSS_ENR_03_BV_pki() runs on ItsPkiHttp system ItsPkiItssSystem {
          // Local variable
          var Headers v_headers;
          var HttpMessage v_request;
          var InnerEcRequest v_inner_ec_request;
          var InnerEcResponse v_inner_ec_response;
          var HashedId8   v_ec_cert_digest;
          var octetstring v_ec_cert_hash;

          // Test component configuration
          f_cfHttpUp(PICS_TS_EA_CERTIFICATE_ID, PICS_TS_AA_CERTIFICATE_ID);
          
          // Test adapter configuration

          // Preamble
          f_init_default_headers_list(-, "inner_ec_response", v_headers);

          if (not(f_await_ec_request_send_response( v_inner_ec_request, v_inner_ec_response, v_request))) {
            log("*** " & testcasename() & ": FAIL: First InnerEcRequest failed ***");
            log("*** " & testcasename() & ":      v_request := ", v_request);
            f_selfOrClientSyncAndVerdict(c_prDone, e_error);
          }
                        
          var HashAlgorithm ha := f_getHashAlgorithmOfVerificationKeyIndicator(v_inner_ec_response.certificate.toBeSigned.verifyKeyIndicator);
          if (ha == sha256) {
            v_ec_cert_hash := f_hashWithSha256(bit2oct(encvalue(v_inner_ec_response.certificate)));
          } else if (ha == sha384) {
            v_ec_cert_hash := f_hashWithSha384(bit2oct(encvalue(v_inner_ec_response.certificate)));
          } else {
            log("*** " & testcasename() & ": FAIL: Unknown EC certificate hash alg=", ha);
            f_selfOrClientSyncAndVerdict(c_prDone, e_error);
          }
          v_ec_cert_digest := substr(v_ec_cert_hash, lengthof(v_ec_cert_hash) - 8, 8);

          log("*** " & testcasename() & ": INFO: First InnerEcRequest received ***");
          log(">>>>> v_inner_ec_response=", v_inner_ec_response);
          log(">>>>> v_ec_cert_hash=", v_ec_cert_hash);
          f_selfOrClientSyncAndVerdict(c_prDone, e_success);

          // Test Body
          tc_ac.start;
          alt {
            [] a_await_ec_http_request_from_iut(mw_http_ec_request_generic, v_request) {
              var integer v_result;
              var Oct16 v_request_hash, v_aes_enc_key;
              var Ieee1609Dot2Data v_decrypted_message;
              var EtsiTs102941Data v_etsi_ts_102941_data;
              var InnerEcResponse  v_inner_ec_response2;
              var Ieee1609Dot2Data v_response_message;

              tc_ac.stop;

              // Verify IUT response
              if (not(f_read_ec_request_from_iut_itss(
                                                      v_request.request.body.binary_body.ieee1609dot2_data,
                                                      v_request_hash, v_aes_enc_key,
                                                      v_decrypted_message,
                                                      v_etsi_ts_102941_data,
                                                      v_inner_ec_request))) {
                f_send_500_Internal_Error(v_headers);
                log("*** " & testcasename() & ": FAIL: Can't parse enrolment request ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }
              
              // send error response to prevent enrolment repetition
              if( not f_http_build_error_ec_response(unknownits, v_request_hash,
                                                  vc_eaPrivateKey, vc_eaWholeHash, v_aes_enc_key,
                                                  v_response_message) ) {
                f_send_500_Internal_Error(v_headers);
                log("*** " & testcasename() & ": FAIL: Can't build enrolment response ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }
              f_http_send(v_headers, m_http_response(
                                                      m_http_response_ok(
                                                              m_http_message_body_binary(
                                                                      m_binary_body_ieee1609dot2_data(v_response_message)
                                                              ), v_headers)));
              
              if( not isvalue(v_inner_ec_request) ){
                log("*** " & testcasename() & ": FAIL: Can't parse enrolment request ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }

              if (not(match(v_inner_ec_request.itsId, v_ec_cert_digest))) {
                log("*** " & testcasename() & ": FAIL: ITS-S ID is not equal to the EC HashedId8 ***");
                log("*** " & testcasename() & ": FAIL:     ", match(v_inner_ec_request.itsId, v_ec_cert_digest));
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }

              if (not(ischosen(v_decrypted_message.content.signedData))) {
                log("*** " & testcasename() & ": FAIL: EC request shall contain signed message ***");
                log("*** " & testcasename() & ": FAIL:     inner data content=", v_decrypted_message.content);
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }

              if (not(ischosen(v_decrypted_message.content.signedData.signer.digest))) {
                log("*** " & testcasename() & ": FAIL: re-keying EC request shall be signed by the previous EC certificate digest***");
                log("*** " & testcasename() & ": FAIL:     signerInfo=", v_decrypted_message.content.signedData.signer);
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }
              
              if (not(f_verifyEcdsa(bit2oct(encvalue(v_decrypted_message.content.signedData.tbsData)),
                                    v_ec_cert_hash,
                                    v_decrypted_message.content.signedData.signature_,
                                    v_inner_ec_response.certificate.toBeSigned.verifyKeyIndicator.verificationKey))) {
                log("*** " & testcasename() & ": FAIL: EC request signature verification failed ***");
                f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
              }
              // Set verdict
              log("*** " & testcasename() & ": PASS: InnerEcRequest received ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
            }
            [] tc_ac.timeout {
              log("*** " & testcasename() & ": INCONC: Expected message not received ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
            }
          } // End of 'alt' statement

          // Postamble
          f_cfHttpDown();
        } // End of function f_TC_SECPKI_ITSS_ENR_03_BV_pki

      } // End of group f_TC_SECPKI_ITSS_ENR_03_BV

      /**
       * @desc If the EC is revoked, the IUT returns to the state 'initialized'.
       * <pre>
       * Pics Selection: PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT and PICS_SECPKI_CRL
       * Expected behaviour:
       *     ensure that {
       *         when {
       *             the IUT is informed about a revocation of its EC
       *         }
       *         then {
       *             the IUT returns to the "initialized" state
       *         }
       *     }
       * </pre>
       * 
       * @see       ETSI TS 103 525-2 v1.2.1 SECPKI_ITSS_ENR_04_BV
       * @reference ETSI TS 102 941, clause 6.1.3, 6.2.3.2.1
       */
      testcase TC_SECPKI_ITSS_ENR_04_BV() runs on ItsMtc system ItsPkiItssSystem {
        // Local variables

        // Test control
        if (not PICS_IUT_ITS_S_ROLE or not PICS_SECPKI_ENROLMENT or not PICS_SECPKI_CRL) {
          log("*** " & testcasename() & ": PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT and PICS_SECPKI_CRL required for executing the TC ***");
          setverdict(inconc);
          stop;
        }

        // Test component configuration

        // Synchronization

        // Cleanup
        setverdict(inconc);

      } // End of TC_SECPKI_ITSS_ENR_04_BV

      /**
       * @desc If the EC expires, the IUT returns to the state 'initialized'.
       * <pre>
       * Pics Selection: PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT
       * Expected behaviour:
       * with
       * 	the IUT being in the 'enrolled' state
       * 	and the EC of the IUT expires 
       * ensure that
       * 	when
       *             the IUT is requested to send an EnrollmentRequestMessage
       * 	then
       *             the IUT sends an EtsiTs103097Data-Encrypted
       *               containing an encrypted EtsiTs103097Data-Signed
       *                 containing EtsiTs102941Data
       *                   containing InnerECRequestSignedForPOP
       *                     containing InnerEcRequest
       *                       containing itsId
       *                         indicating the canonical identifier of the ITS-S 
       * </pre>
       * 
       * @see       ETSI TS 103 525-2 v1.2.1 SECPKI_ITSS_ENR_05_BV
       * @reference ETSI TS 102 941, clause 6.1.3, 6.2.3.2.1
       */
      testcase TC_SECPKI_ITSS_ENR_05_BV() runs on ItsMtc system ItsPkiItssSystem {
        // Local variables
        var Oct32      v_private_key;
        var Oct32      v_public_key_x;
        var Oct32      v_public_key_y;
        var Oct32      v_public_compressed_key;
        var integer    v_compressed_mode;
        var ItsPkiItss v_itss;
        var ItsPkiHttp v_ea;

        // Test control
        if (not PICS_IUT_ITS_S_ROLE or not PICS_SECPKI_ENROLMENT) {
          log("*** " & testcasename() & ": PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT required for executing the TC ***");
          setverdict(inconc);
          stop;
        }

        // Test component configuration
        f_cfMtcUp01(v_itss, v_ea);

        // Start components
        v_itss.start(f_TC_SECPKI_ITSS_ENR_05_BV_itss()); // wait 15 sec before the second enrolment
        v_ea.start(f_TC_SECPKI_ITSS_ENR_05_BV_pki());

        // Synchronization
        f_serverSync2ClientsAndStop({c_prDone, c_tbDone});

        // Cleanup
        f_cfMtcDown01(v_itss, v_ea);

      } // End of TC_SECPKI_ITSS_ENR_05_BV

      group f_TC_SECPKI_ITSS_ENR_05_BV {

        function f_TC_SECPKI_ITSS_ENR_05_BV_itss() runs on ItsPkiItss system ItsPkiItssSystem {
          // Test component configuration
          
          // Test adapter configuration
          
          // Preamble
          // Initial state: No CAM shall be emitted
          geoNetworkingPort.clear;
          tc_noac.start;
          alt {
            [] geoNetworkingPort.receive {
              log("No CA message expected");
              f_selfOrClientSyncAndVerdict(c_prDone, e_error);
            }
            [] tc_noac.timeout {
              // Trigger the first enrolment
              log("*** " & testcasename() & "_itss: INFO: No CA message received ***");
            } 
          } // End of 'alt' statement
          log("*** " & testcasename() & "_itss: INFO: Trigger 1st emrolment ***");
          f_sendUtTriggerEnrolmentRequestPrimitive();
          
          // wait a couple of seconds and run second enrolment to check re-enrolment procedure
          f_sleep(PX_RE_ENROLMENT_DELAY);
          log("*** " & testcasename() & "_itss: INFO: Trigger 2nd emrolment ***");
          f_sendUtTriggerEnrolmentRequestPrimitive();

          // wait 5 seconds after expiration of EC cert
          f_sleep(PX_CERT_EXPIRATION_DELAY + 5.0);

          f_selfOrClientSyncAndVerdict(c_prDone, e_success);

          // Test Body
          // Trigger the 3rd enrolment
          log("*** " & testcasename() & "_itss: INFO: Trigger 3rd emrolment ***");
          f_sendUtTriggerEnrolmentRequestPrimitive();

          log("*** " & testcasename() & "_itss: PASS: Re-enrolment trigger sent succesfully ***");
          f_selfOrClientSyncAndVerdict(c_tbDone, e_success);

          // Postamble
          f_cfDown_itss();
        } // End of function f_TC_SECPKI_ITSS_ENR_03_BV_itss

        function f_TC_SECPKI_ITSS_ENR_05_BV_pki() runs on ItsPkiHttp system ItsPkiItssSystem {
          // Local variable
          var Headers v_headers;
          var HttpMessage v_request;
          var InnerEcRequest v_inner_ec_request;
          var InnerEcResponse v_inner_ec_response;
          var HashedId8   v_ec_cert_digest;
          var EtsiTs103097Certificate v_ec_cert;
          
          // Test component configuration
          f_cfHttpUp(PICS_TS_EA_CERTIFICATE_ID, PICS_TS_AA_CERTIFICATE_ID);

          f_init_default_headers_list(-, "inner_ec_response", v_headers);
          
          // Preamble
          if (not(f_await_ec_request_send_response(v_inner_ec_request, v_inner_ec_response, v_request,
                                                   ok,
                                                   m_certificateSubjectAttributes_id_omit(
                                                                                          -,
                                                                                          valueof(m_validityPeriod(f_getCurrentTime() / 1000, 
                                                                                                  m_duration_in_seconds(float2int(PX_CERT_EXPIRATION_DELAY))))
                                                   )))) {
            log("*** " & testcasename() & ": FAIL: First InnerEcRequest failed ***");
            log("*** " & testcasename() & ":      v_request := ", v_request);
            f_selfOrClientSyncAndVerdict(c_prDone, e_error);
          }
          log(">>>>> 1st v_inner_ec_response=", v_inner_ec_response);

          v_ec_cert := v_inner_ec_response.certificate;
          v_ec_cert_digest := f_calculateDigestFromCertificate(v_ec_cert);

          if (not(ischosen(v_ec_cert.toBeSigned.validityPeriod.duration.seconds))) {
            log("*** " & testcasename() & ": INCONC: wrong EC certificate validity period error");
            f_selfOrClientSyncAndVerdict(c_prDone, e_error);
          }
          log("*** " & testcasename() & ": INFO: First InnerEcRequest processed. EC = " & oct2str(v_ec_cert_digest) & "***");
          log("*** " & testcasename() & ": INFO:                                      expires in " 
               & int2str(v_ec_cert.toBeSigned.validityPeriod.start_ + v_ec_cert.toBeSigned.validityPeriod.duration.seconds - (f_getCurrentTime()/1000))
               & " seconds ***"
          );
          
          // Wait for 2nd request with EC data
          if (not(f_await_ec_request_send_response( v_inner_ec_request, v_inner_ec_response, v_request, deniedrequest))) {
            log("*** " & testcasename() & ": FAIL: 2nd InnerEcRequest failed ***");
            log("*** " & testcasename() & ":      v_request := ", v_request);
            f_selfOrClientSyncAndVerdict(c_prDone, e_error);
          }
          log(">>>>> 2nd v_inner_ec_response=", v_inner_ec_response);

          if (not(match(v_inner_ec_request.itsId, v_ec_cert_digest))) {
            log("*** " & testcasename() & ": FAIL: ITS-S ID of 2nd request must be equal to the EC HashedId8 ***");
            log("*** " & testcasename() & ": FAIL:     ", match(v_inner_ec_request.itsId, v_ec_cert_digest));
            f_selfOrClientSyncAndVerdict(c_prDone, e_error);
          }
          f_selfOrClientSyncAndVerdict(c_prDone, e_success);

          // Test Body
          if (not(f_await_ec_request_send_response( v_inner_ec_request, v_inner_ec_response, v_request, deniedrequest))){
            log("*** " & testcasename() & ": FAIL: 3rd InnerEcRequest failed ***");
            log("*** " & testcasename() & ":      v_request := ", v_request);
            f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
          }
          log(">>>>> 3rd v_inner_ec_response=", v_inner_ec_response);

          if(match(v_inner_ec_request.itsId, v_ec_cert_digest)){
            if(v_ec_cert.toBeSigned.validityPeriod.start_ + v_ec_cert.toBeSigned.validityPeriod.duration.seconds < (f_getCurrentTime()/1000)){
              log("*** " & testcasename() & ": INCONC: EC certificate is not expired yet ***");
              f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
            }
            log("*** " & testcasename() & ": FAIL: ITS-S ID of 3rd request must NOT be equal to the expired EC HashedId8 ***");
            log("*** " & testcasename() & ": FAIL:     ", match(v_inner_ec_request.itsId, v_ec_cert_digest));
            f_selfOrClientSyncAndVerdict(c_tbDone, e_error);
          }
          f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
          
          // Postamble
          f_cfHttpDown();
        } // End of function f_TC_SECPKI_ITSS_ENR_05_BV_pki

      } // End of group f_TC_SECPKI_ITSS_ENR_05_BV

      /**
       * @desc For each enrolment request, the ITS-S shall generate a new verification key pair 
               corresponding to an approved signature algorithm as specified in TS 103 097.
       * <pre>
       * Pics Selection: PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT and not PICS_SECPKI_REENROLMENT
       * Expected behaviour:
       *     ensure that {
       *         when {
       *             the IUT is requested to send multiple EnrolmentRequestMessage
       *         }
       *         then {
       *             each EnrolmentRequestMessage
       *                 contains a different and unique verification key pair within the InnerECRequest
       *         }
       *     }
       * </pre>
       * 
       * @see       ETSI TS 103 525-2 v1.2.1 SECPKI_ITSS_ENR_06_BV
       * @reference ETSI TS 102 941, clause 6.1.3
       */
      testcase TC_SECPKI_ITSS_ENR_06_BV_1() runs on ItsMtc system ItsPkiItssSystem {
        f_TC_SECPKI_ITSS_ENR_06_BV_mtc(c_stInitial);
      } // End of TC_SECPKI_ITSS_ENR_06_BV_1
      testcase TC_SECPKI_ITSS_ENR_06_BV_2() runs on ItsMtc system ItsPkiItssSystem {
        f_TC_SECPKI_ITSS_ENR_06_BV_mtc(c_stEnrolled);
      } // End of TC_SECPKI_ITSS_ENR_06_BV_2

      group f_TC_SECPKI_ITSS_ENR_06_BV_mtc {

        function f_TC_SECPKI_ITSS_ENR_06_BV_mtc(
                                                in charstring p_state
                                                ) runs on ItsMtc system ItsPkiItssSystem {
          // Local variables
          var ItsPkiItss v_itss;
          var ItsPkiHttp v_ea;

          // Test control
          if (not PICS_IUT_ITS_S_ROLE or not PICS_SECPKI_ENROLMENT) {
            log("*** " & testcasename() & ": PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT required for executing the TC ***");
            setverdict(inconc);
            stop;
          }

          // Test component configuration
          f_cfMtcUp01(v_itss, v_ea);

          // Start components
          v_itss.start(f_TC_SECPKI_ITSS_ENR_06_BV_itss(PX_RE_ENROLMENT_COUNTER, p_state));
          v_ea.start(f_TC_SECPKI_ITSS_ENR_06_BV_pki(PX_RE_ENROLMENT_COUNTER, p_state));

          // Synchronization
          f_serverSyncClientsTimed(2, c_prDone, PX_TSYNC_TIME_LIMIT);
        
          for(var integer v_i := 0; v_i < PX_RE_ENROLMENT_COUNTER; v_i := v_i + 1){
            f_serverSyncClientsTimed(2, c_nextTry, PX_TSYNC_TIME_LIMIT);
          }
          f_serverSyncClientsTimed(2, c_tbDone, PX_TSYNC_TIME_LIMIT);

          // Cleanup
          f_serverWaitForAllClientsToStop();        
        } // End of f_TC_SECPKI_ITSS_ENR_06_BV_mtc

        function f_TC_SECPKI_ITSS_ENR_06_BV_itss(
                                                integer p_max_try,
                                                charstring p_state
                                                ) runs on ItsPkiItss system ItsPkiItssSystem {
          // Local variables
          var EtsiTs103097Certificate v_certificate;

          // Test component configuration

          // Test adapter configuration

          // Preamble
          // Initial state: No CAM shall be emitted
          geoNetworkingPort.clear;
          tc_noac.start;
          alt {
            [] geoNetworkingPort.receive {
              log("No CA message expected");
              f_selfOrClientSyncAndVerdict(c_prDone, e_error);
            }
            [] tc_noac.timeout {
              log("*** " & testcasename() & "_itss: : INFO: No CA message received ***");
              f_selfOrClientSyncAndVerdict(c_prDone, e_success);
            } 
          } // End of 'alt' statement

          // Test Body
          // Send first enrolment
          for(var integer v_i := 0; v_i < p_max_try; v_i := v_i + 1){
            f_sleep(PX_RE_ENROLMENT_DELAY);
            f_sendUtTriggerEnrolmentRequestPrimitive();
            f_clientSync(c_nextTry, e_success);
          }

          f_selfOrClientSyncAndVerdict(c_tbDone, e_success);

          // Postamble
          f_cfDown_itss();
        } // End of function f_TC_SECPKI_ITSS_ENR_06_BV_itss

        function f_TC_SECPKI_ITSS_ENR_06_BV_pki(
                                                integer p_max_try, 
                                                charstring p_state
                                                ) runs on ItsPkiHttp system ItsPkiItssSystem {
          // Local variable
          var Headers v_headers;
          var ListOfPublicVerificationKey v_generated_keys;

          // Test component configuration
          f_cfHttpUp();

          // Test adapter configuration

          // Preamble
          f_init_default_headers_list(-, "inner_ec_response", v_headers);
          f_selfOrClientSyncAndVerdict(c_prDone, e_success);

          // Test Body
          for (var integer v_i := 0; v_i < p_max_try; v_i := v_i + 1) {
            var HttpMessage v_request;
            var InnerEcRequest v_inner_ec_request;
            var InnerEcResponse v_inner_ec_response;
            var PublicVerificationKey v_key;
            var EnrolmentResponseCode v_response_code;

            if(p_state == c_stInitial){
              v_response_code := deniedrequest;
            } else {
              v_response_code := ok;
            }
            
            if (not(f_await_ec_request_send_response( v_inner_ec_request, v_inner_ec_response, v_request, v_response_code))) {
              log("*** " & testcasename() & ": ERROR: EC request receiving error ***");
              setverdict(inconc);
              f_clientSync(c_nextTry, e_error);
            }

            v_key := v_inner_ec_request.publicKeys.verificationKey;

            if (isbound(v_generated_keys) and match(v_generated_keys, superset(v_key))) {
              log("*** " & testcasename() & ": LOG: ", match(v_generated_keys, superset(v_key)), "***");
              log("*** " & testcasename() & ": FAIL: Duplication of generated public keys ***");
              setverdict(fail);
              f_clientSync(c_nextTry, e_error);
            }
            v_generated_keys[v_i] := v_key;

            f_clientSync(c_nextTry, e_success);
          }
          log("*** " & testcasename() & ": PASS: No identical verification keys received in " & int2str(p_max_try) & " messages ***");
          f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_success);

          // Postamble
          f_cfHttpDown();
        } // End of function f_TC_SECPKI_ITSS_ENR_06_BV_pki

      } // End of group f_TC_SECPKI_ITSS_ENR_06_BV

      /**
       * @desc Within the InnerECRequest, the requestedSubjectAttributes shall not contain a certIssuePermissions field.
       * <pre>
       * Pics Selection: PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT
       * Expected behaviour:
       *     ensure that {
       *         when {
       *             the IUT is requested to send an EnrolmentRequestMessage
       *         }
       *         then {
       *             the IUT sends an EtsiTs103097Data-Encrypted
       *                 containing an encrypted EtsiTs103097Data-Signed
       *                     containing EtsiTs103097Data
       *                         containing InnerECRequestSignedForPOP
       *                             containing InnerEcRequest
       *                                 containing requestedSubjectAttributes
       *                                     not containing certIssuePermissions 
       *         }
       *     }
       * </pre>
       * 
       * @see       ETSI TS 103 525-2 v1.2.1 SECPKI_ITSS_ENR_07_BV
       * @reference ETSI TS 102 941, clause 6.2.3.2.1
       */
      testcase TC_SECPKI_ITSS_ENR_07_BV() runs on ItsMtc system ItsPkiItssSystem {
        // Local variables
        var Oct32      v_private_key;
        var Oct32      v_public_key_x;
        var Oct32      v_public_key_y;
        var Oct32      v_public_compressed_key;
        var integer    v_compressed_mode;
        var ItsPkiItss v_itss;
        var ItsPkiHttp v_ea;

        // Test control
        if (not PICS_IUT_ITS_S_ROLE or not PICS_SECPKI_ENROLMENT) {
          log("*** " & testcasename() & ": PICS_IUT_ITS_S_ROLE and PICS_SECPKI_ENROLMENT required for executing the TC ***");
          setverdict(inconc);
          stop;
        }

        // Test component configuration
        f_cfMtcUp01(v_itss, v_ea);

        // Start components
        v_itss.start(f_TC_SECPKI_ITSS_ENR_01_BV_itss());