LibItsPki_Functions.ttcn 345 KB
Newer Older
ASN.1 Documenter's avatar
ASN.1 Documenter committed
/**
 *  @author   ETSI / STF544
 *  @version  $Url$
 *            $Id$
 *  @desc     Module containing functions for ITS PKI ATS
 *  @copyright   ETSI Copyright Notification
 *               No part may be reproduced except as authorized by written permission.
 *               The copyright and the foregoing restriction extend to reproduction in all media.
 *               All rights reserved.
 *
 */
module LibItsPki_Functions {
    
  // LibCommon
  import from LibCommon_Time all;
  import from LibCommon_VerdictControl all;
  import from LibCommon_Sync all;
  import from LibCommon_BasicTypesAndValues all;
  import from LibCommon_DataStrings all;
  
  // LibHelpers
  import from LibHelpers_Functions all;

ASN.1 Documenter's avatar
ASN.1 Documenter committed
  // LibIts
  import from Ieee1609Dot2BaseTypes language "ASN.1:1997" all;
  import from Ieee1609Dot2 language "ASN.1:1997" all;
  import from EtsiTs102941BaseTypes language "ASN.1:1997" all;
  import from EtsiTs102941TypesEnrolment language "ASN.1:1997" all;
  import from EtsiTs102941TypesAuthorization language "ASN.1:1997" all;
  import from EtsiTs102941TypesAuthorizationValidation language "ASN.1:1997" all;
  import from EtsiTs102941MessagesCa language "ASN.1:1997" all;
  import from EtsiTs102941TrustLists language "ASN.1:1997" all;
  import from EtsiTs103097Module language "ASN.1:1997" all;
  import from ETSI_ITS_CDD language "ASN.1:1997" all;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
  import from CAM_PDU_Descriptions language "ASN.1:1997" all;
  
  // LibItsCommon
  import from LibItsCommon_TypesAndValues all;
  import from LibItsCommon_Functions all;
  import from LibItsCommon_ASN1_NamedNumbers all;
  import from LibItsCommon_Pixits all;
  
  // LibItsGeoNetworking
  import from LibItsGeoNetworking_TypesAndValues all;
  import from LibItsGeoNetworking_TestSystem all;
  import from LibItsGeoNetworking_Pixits all;
  
  // LibItsSecurity
  import from LibItsSecurity_TypesAndValues all;
  import from LibItsSecurity_Templates all;
  import from LibItsSecurity_Functions all;
  import from LibItsSecurity_Pics all;
  import from LibItsSecurity_Pixits all;
  import from LibItsSecurity_TestSystem all;
  
  // LibHttp
  import from LibHttp_TypesAndValues all;
  import from LibHttp_Templates all;
  import from LibHttp_Functions all;
  import from LibHttp_TestSystem all;
  import from LibHttp_Pics all;

  // LibHttp
  import from LibHttp_BinaryTemplates all;

ASN.1 Documenter's avatar
ASN.1 Documenter committed
  // LibItsPki
  import from LibItsPki_TypesAndValues all;
  import from LibItsPki_Templates all;
  import from LibItsPki_Pics all;
  import from LibItsPki_Pixits all;
  import from LibItsPki_TestSystem all;
  
  group pkiConfigurationFunctions {

    function f_cfMtcUp01(
                         out ItsPkiItss p_itss,
                         out ItsPkiHttp p_pki
                         ) runs on ItsMtc {
      p_itss := ItsPkiItss.create("ITS-S") alive;
      p_pki := ItsPkiHttp.create("PKI") alive;
      
      connect(self:syncPort, mtc:syncPort);
      connect(p_itss:syncPort, self:syncPort);
      connect(p_pki:syncPort, self:syncPort);
      
      connect(p_pki:infoPort, p_itss:infoPort);
    } // End of function f_cfMtcUp01
    
    function f_cfMtcUp02(
                         out ItsPkiHttp p_itss,
                         out ItsPkiHttp p_ea
                         ) runs on ServerSyncComp {
      p_itss := ItsPkiItss.create("ITS-S") alive;
      p_ea := ItsPkiHttp.create("EA") alive;
      
      connect(self:syncPort, mtc:syncPort);
      connect(p_itss:syncPort, self:syncPort);
      connect(p_ea:syncPort, self:syncPort);
    } // End of function f_cfMtcUp02
    
    function f_cfMtcUp03(
                         out ItsPkiHttp p_itss,
                         out ItsPkiHttp p_tlm
                         ) runs on ServerSyncComp {
      p_itss := ItsPkiItss.create("ITS-S") alive;
      p_tlm := ItsPkiHttp.create("TLM") alive;
      
      connect(self:syncPort, mtc:syncPort);
      connect(p_itss:syncPort, self:syncPort);
      connect(p_tlm:syncPort, self:syncPort);
    } // End of function f_cfMtcUp03
    
    function f_cfMtcUp04(
                         out ItsPkiHttp p_itss,
                         out ItsPkiHttp p_dc
                         ) runs on ServerSyncComp {
      p_itss := ItsPkiItss.create("ITS-S") alive;
      p_dc := ItsPkiHttp.create("DC") alive;
      
      connect(self:syncPort, mtc:syncPort);
      connect(p_itss:syncPort, self:syncPort);
      connect(p_dc:syncPort, self:syncPort);
    } // End of function f_cfMtcUp04
    
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    /**
     * @desc    Setups default configuration
     * @param   p_certificate_id The certificate identifier the TA shall use in case of secured IUT
     */
    function f_cfHttpUp(
                        in charstring p_ea_certificate_id := "CERT_TS_A_EA", // TODO Use a constant
                        in charstring p_aa_certificate_id := "CERT_TS_A_AA"
                        ) runs on ItsPkiHttp system ItsPkiHttpSystem {

      if (PICS_MULTIPLE_END_POINT == false) {
        map(self:httpPort, system:httpPort);
      } else {
        map(self:httpEcPort, system:httpEcPort);
        map(self:httpAtVPort, system:httpAtVPort);
        map(self:httpAtPort, system:httpAtPort);
      }
      f_connect4SelfOrClientSync();

      f_initialiseSecuredMode(p_ea_certificate_id, p_aa_certificate_id); // TODO To be removed???

      // TODO Duplicate code, use a function
      
      // Setup EA certificate shared with PKI EA entity
      f_readCertificate(p_ea_certificate_id, vc_eaCertificate);
      f_readSigningKey(p_ea_certificate_id, vc_eaPrivateKey); // TODO To be removed
      f_readEncryptingKey(p_ea_certificate_id, vc_eaPrivateEncKey);
      f_getCertificateDigest(p_ea_certificate_id, vc_eaHashedId8);
      f_getCertificateHash(p_ea_certificate_id, vc_eaWholeHash);
      f_getCertificateHash256(p_ea_certificate_id, vc_eaWholeHash256);
      log("f_cfHttpUp: vc_eaPrivateKey= ", vc_eaPrivateKey);
      log("f_cfHttpUp: vc_eaPrivateEncKey= ", vc_eaPrivateEncKey);
      log("f_cfHttpUp: vc_eaHashedId8= ", vc_eaHashedId8);
      log("f_cfHttpUp: vc_eaWholeHash= ", vc_eaWholeHash);
      log("f_cfHttpUp: vc_eaWholeHash256= ", vc_eaWholeHash256);
      
      // Setup AA certificate shared with PKI AA entity
      f_readCertificate(p_aa_certificate_id, vc_aaCertificate);
      f_readSigningKey(p_aa_certificate_id, vc_aaPrivateKey); // Required for AuthorizationValidation request
      f_readEncryptingKey(p_aa_certificate_id, vc_aaPrivateEncKey);
      f_getCertificateDigest(p_aa_certificate_id, vc_aaHashedId8);
      f_getCertificateHash(p_aa_certificate_id, vc_aaWholeHash);
      f_getCertificateHash256(p_aa_certificate_id, vc_aaWholeHash256);
      log("f_cfHttpUp: vc_aaPrivateKey= ", vc_aaPrivateKey);
      log("f_cfHttpUp: vc_aaPrivateEncKey= ", vc_aaPrivateEncKey);
      log("f_cfHttpUp: vc_aaHashedId8= ", vc_aaHashedId8);
      log("f_cfHttpUp: vc_aaWholeHash= ", vc_aaWholeHash);
      log("f_cfHttpUp: vc_aaWholeHash256= ", vc_aaWholeHash256);

      // Storage of enrolment keys in case of re-enrolment
      vc_ec_keys_counter := 0;
      vc_ec_counter := 0;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      vc_ec_private_keys := {};
      vc_ec_public_compressed_key := {};
      vc_ec_compressed_modes := {};
      vc_ec_hashed_id8 := {};
      vc_ec_certificates := {};

      if (PICS_MULTIPLE_END_POINT == false) {
        activate(a_default_pki_http());
      } else {
        activate(a_default_pki_http_ec());
        activate(a_default_pki_http_atv());
        activate(a_default_pki_http_at());
      }
    } // End of function f_cfHttpUp
    
    /**
     * @desc    Setups default configuration
     */
    function f_cfHttpUp_ca() runs on ItsPkiHttp system ItsPkiHttpSystem { // FIXME Rename into f_cfHttpUp_rca_dc
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      if (PICS_MULTIPLE_END_POINT == false) {
        map(self:httpPort, system:httpPort);
      } else {
        map(self:httpCaPort, system:httpCaPort);
      }
      f_connect4SelfOrClientSync();

      f_initialiseSecuredMode();

      if (PICS_MULTIPLE_END_POINT == false) {
        activate(a_default_pki_http());
      } else {
        activate(a_default_pki_http_ca());
      }
    } // End of function f_cfHttpUp_ca
    
    /**
     * @desc    Setups default configuration
     */
    function f_cfHttpUp_tlm() runs on ItsPkiHttp system ItsPkiHttpSystem { // FIXME Rename into f_cfHttpUp_cpoc
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      if (PICS_MULTIPLE_END_POINT == false) {
        map(self:httpPort, system:httpPort);
      } else {
        map(self:httpTlmPort, system:httpTlmPort);
      }
      f_connect4SelfOrClientSync();

      f_initialiseSecuredMode();

      if (PICS_MULTIPLE_END_POINT == false) {
        activate(a_default_pki_http());
      } else {
        activate(a_default_pki_http_tlm());
      }
    } // End of function f_cfHttpUp_tlm
    
    /**
     * @desc    Setups default configuration
     * @param   p_certificate_id The certificate identifier the TA shall use in case of secured IUT
     */
    function f_cfHttpUp_itss(
                             in charstring p_ea_certificate_id := "CERT_TS_A_EA", // TODO Use a constant
                             in charstring p_aa_certificate_id := "CERT_TS_A_AA"
                             ) runs on ItsPkiHttp system ItsPkiHttpSystem {

      if (PICS_MULTIPLE_END_POINT == false) {
        map(self:httpPort, system:httpPort);
      } else {
        map(self:httpEcPort, system:httpEcPort);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        map(self:httpAtPort, system:httpAtPort);
      }

      f_initialiseSecuredMode(p_ea_certificate_id, p_aa_certificate_id); // TODO To be removed???

      // TODO Duplicate code, use a function
      
      // Setup EA certificate shared with PKI EA entity
      f_readCertificate(p_ea_certificate_id, vc_eaCertificate);
      f_readSigningKey(p_ea_certificate_id, vc_eaPrivateKey); // TODO To be removed
      f_readEncryptingKey(p_ea_certificate_id, vc_eaPrivateEncKey);
      f_getCertificateDigest(p_ea_certificate_id, vc_eaHashedId8);
      f_getCertificateHash(p_ea_certificate_id, vc_eaWholeHash);
      f_getCertificateHash256(p_ea_certificate_id, vc_eaWholeHash256);
      log("f_cfHttpUp_itss: vc_eaPrivateKey= ", vc_eaPrivateKey);
      log("f_cfHttpUp_itss: vc_eaPrivateEncKey= ", vc_eaPrivateEncKey);
      log("f_cfHttpUp_itss: vc_eaHashedId8= ", vc_eaHashedId8);
      log("f_cfHttpUp_itss: vc_eaWholeHash= ", vc_eaWholeHash);
      log("f_cfHttpUp: vc_eaWholeHash256= ", vc_eaWholeHash256);
      
      // Setup AA certificate shared with PKI AA entity
      f_readCertificate(p_aa_certificate_id, vc_aaCertificate);
      f_readSigningKey(p_aa_certificate_id, vc_aaPrivateKey); // Required for AuthorizationValidation request
      f_readEncryptingKey(p_aa_certificate_id, vc_aaPrivateEncKey);
      f_getCertificateDigest(p_aa_certificate_id, vc_aaHashedId8);
      f_getCertificateHash(p_aa_certificate_id, vc_aaWholeHash);
      f_getCertificateHash256(p_aa_certificate_id, vc_aaWholeHash256);
      log("f_cfHttpUp_itss: vc_aaPrivateKey= ", vc_aaPrivateKey);
      log("f_cfHttpUp_itss: vc_aaPrivateEncKey= ", vc_aaPrivateEncKey);
      log("f_cfHttpUp_itss: vc_aaHashedId8= ", vc_aaHashedId8);
      log("f_cfHttpUp_itss: vc_aaWholeHash= ", vc_aaWholeHash);
      log("f_cfHttpUp: vc_eaWholeHash256= ", vc_aaWholeHash256);

      // Storage of enrolment keys in case of re-enrolment
      vc_ec_keys_counter := 0;
      vc_ec_counter := 0;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      vc_ec_private_keys := {};
      vc_ec_public_compressed_key := {};
      vc_ec_compressed_modes := {};
      vc_ec_hashed_id8 := {};
      vc_ec_certificates := {};

      if (PICS_MULTIPLE_END_POINT == false) {
        activate(a_default_pki_http());
      } else {
        activate(a_default_pki_http_at());
      }
    } // End of function f_cfHttpUp_itss
    
    /**
     * @desc    Setups default configuration
     * @param   p_certificate_id The certificate identifier the TA shall use in case of secured IUT
     */
    function f_cfHttpUp_ea(
                           in charstring p_ea_certificate_id := "CERT_TS_A_EA", // TODO Use a constant
                           in charstring p_aa_certificate_id := "CERT_TS_A_AA"
                           ) runs on ItsPkiHttp system ItsPkiHttpSystem {
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      if (PICS_MULTIPLE_END_POINT == false) {
        map(self:httpPort, system:httpPort);
      } else {
        map(self:httpAtVPort, system:httpAtVPort);
      }

      f_initialiseSecuredMode(p_ea_certificate_id, p_aa_certificate_id); // TODO To be removed???

      // TODO Duplicate code, use a function
      
      // Setup EA certificate shared with PKI EA entity
      f_readCertificate(p_ea_certificate_id, vc_eaCertificate);
      f_readSigningKey(p_ea_certificate_id, vc_eaPrivateKey); // TODO To be removed
      f_readEncryptingKey(p_ea_certificate_id, vc_eaPrivateEncKey);
      f_getCertificateDigest(p_ea_certificate_id, vc_eaHashedId8);
      f_getCertificateHash(p_ea_certificate_id, vc_eaWholeHash);
      f_getCertificateHash256(p_aa_certificate_id, vc_eaWholeHash256);
      log("f_cfHttpUp_ea: vc_eaPrivateKey= ", vc_eaPrivateKey);
      log("f_cfHttpUp_ea: vc_eaPrivateEncKey= ", vc_eaPrivateEncKey);
      log("f_cfHttpUp_ea: vc_eaHashedId8= ", vc_eaHashedId8);
      log("f_cfHttpUp_ea: vc_eaWholeHash= ", vc_eaWholeHash);
      log("f_cfHttpUp: vc_aaWholeHash256= ", vc_eaWholeHash256);
      
      // Setup AA certificate shared with PKI AA entity
      f_readCertificate(p_aa_certificate_id, vc_aaCertificate);
      f_readSigningKey(p_aa_certificate_id, vc_aaPrivateKey); // Required for AuthorizationValidation request
      f_readEncryptingKey(p_aa_certificate_id, vc_aaPrivateEncKey);
      f_getCertificateDigest(p_aa_certificate_id, vc_aaHashedId8);
      f_getCertificateHash(p_aa_certificate_id, vc_aaWholeHash);
      f_getCertificateHash256(p_aa_certificate_id, vc_aaWholeHash256);
      log("f_cfHttpUp_ea: vc_aaPrivateKey= ", vc_aaPrivateKey);
      log("f_cfHttpUp_ea: vc_aaPrivateEncKey= ", vc_aaPrivateEncKey);
      log("f_cfHttpUp_ea: vc_aaHashedId8= ", vc_aaHashedId8);
      log("f_cfHttpUp_ea: vc_aaWholeHash= ", vc_aaWholeHash);
      log("f_cfHttpUp: vc_aaWholeHash256= ", vc_aaWholeHash256);

      // Storage of enrolment keys in case of re-enrolment
      vc_ec_keys_counter := 0;
      vc_ec_counter := 0;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      vc_ec_private_keys := {};
      vc_ec_public_compressed_key := {};
      vc_ec_compressed_modes := {};
      vc_ec_hashed_id8 := {};
      vc_ec_certificates := {};

      if (PICS_MULTIPLE_END_POINT == false) {
        activate(a_default_pki_http());
      } else {
        activate(a_default_pki_http_atv());
        activate(a_default_pki_http_at());
      }
    } // End of function f_cfHttpUp_ea
    
    function f_cfUp_itss() runs on ItsPkiItss system ItsPkiItssSystem {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      
      map(self:geoNetworkingPort, system:geoNetworkingPort);
      map(self:utPort, system:utPort);
      //map(self:acPort, system:acPort);
      
      f_initializeState();
      
      // activate(a_default_pki()); TOTO Defualt from geoNet
    } // End of function f_cfUp_itss

    /**
     * @desc    Deletes default configuration 
     */
    function f_cfMtcDown01(
                           inout ItsPkiItss p_itss,
                           inout ItsPkiHttp p_pki
                           ) runs on ItsMtc {
      disconnect(self:syncPort, mtc:syncPort);
      disconnect(p_itss:syncPort, self:syncPort);
      disconnect(p_pki:syncPort, self:syncPort);
      
      disconnect(p_pki:infoPort, p_itss:infoPort);
      
      p_itss.done;
      p_pki.done;
    }
    
    function f_cfMtcDown02(
                           inout ItsPkiHttp p_itss,
                           inout ItsPkiHttp p_ea
                           ) runs on ServerSyncComp {
      disconnect(self:syncPort, mtc:syncPort);
      disconnect(p_itss:syncPort, self:syncPort);
      disconnect(p_ea:syncPort, self:syncPort);
      
      p_itss.done;
      p_ea.done;
    }
    
    function f_cfMtcDown03(
                           inout ItsPkiHttp p_itss,
                           inout ItsPkiHttp p_tlm
                           ) runs on ServerSyncComp {
      disconnect(self:syncPort, mtc:syncPort);
      disconnect(p_itss:syncPort, self:syncPort);
      disconnect(p_tlm:syncPort, self:syncPort);
      
      p_itss.done;
      p_tlm.done;
    }
    
    function f_cfMtcDown04(
                           inout ItsPkiHttp p_itss,
                           inout ItsPkiHttp p_dc
                           ) runs on ServerSyncComp {
      disconnect(self:syncPort, mtc:syncPort);
      disconnect(p_itss:syncPort, self:syncPort);
      disconnect(p_dc:syncPort, self:syncPort);
      
      p_itss.done;
      p_dc.done;
    }
    
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    /**
     * @desc    Deletes default configuration 
     */
    function f_cfHttpDown() runs on ItsPkiHttp {
      if (PICS_MULTIPLE_END_POINT == false) {
        unmap(self:httpPort, system:httpPort);
      } else {
        unmap(self:httpEcPort, system:httpEcPort);
        unmap(self:httpAtVPort, system:httpAtVPort);
        unmap(self:httpAtPort, system:httpAtPort);
      }
      f_disconnect4SelfOrClientSync();
      f_uninitialiseSecuredMode();
    } // End of function f_cfHttpDown
    
    /**
     * @desc    Deletes default configuration 
     */
    function f_cfHttpDown_ca() runs on ItsPkiHttp {
      if (PICS_MULTIPLE_END_POINT == false) {
        unmap(self:httpPort, system:httpPort);
      } else {
        unmap(self:httpCaPort, system:httpCaPort);
      }
      f_disconnect4SelfOrClientSync();
      f_uninitialiseSecuredMode();
    } // End of function f_cfHttpDown_ca
    
    /**
     * @desc    Deletes default configuration 
     */
    function f_cfHttpDown_tlm() runs on ItsPkiHttp {
      if (PICS_MULTIPLE_END_POINT == false) {
        unmap(self:httpPort, system:httpPort);
      } else {
        unmap(self:httpTlmPort, system:httpTlmPort);
      }
      f_disconnect4SelfOrClientSync();
      f_uninitialiseSecuredMode();
    } // End of function f_cfHttpDown_tlm
    
    /**
     * @desc    Deletes default configuration 
     */
    function f_cfHttpDown_itss() runs on ItsPkiHttp {
      if (PICS_MULTIPLE_END_POINT == false) {
        unmap(self:httpPort, system:httpPort);
      } else {
        unmap(self:httpEcPort, system:httpEcPort);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        unmap(self:httpAtPort, system:httpAtPort);
      }
      f_disconnect4SelfOrClientSync();
      f_uninitialiseSecuredMode();
    } // End of function f_cfHttpDown_itss
    
    /**
     * @desc    Deletes default configuration 
     */
    function f_cfHttpDown_ea() runs on ItsPkiHttp {
      if (PICS_MULTIPLE_END_POINT == false) {
        unmap(self:httpPort, system:httpPort);
      } else {
        unmap(self:httpAtVPort, system:httpAtVPort);
      }
      f_disconnect4SelfOrClientSync();
      f_uninitialiseSecuredMode();
    } // End of function f_cfHttpDown_ea
    
    /**
     * @desc    Deletes default configuration 
     */
    function f_cfDown_itss() runs on ItsPkiItss system ItsPkiItssSystem {
      unmap(self:geoNetworkingPort, system:geoNetworkingPort);
      unmap(self:utPort, system:utPort);
      //unmap(self:acPort, system:acPort);
      
    } // End of function f_cfDown
    
    /**
     * @desc Initialise secure mode if required
     */
    function f_initialiseSecuredMode(
                                     in charstring p_certificate_id  := "CERT_TS_A_EA", // TODO Use a constant
                                     in charstring p_peerCertificateId := "CERT_IUT_A_EA"
                                     ) runs on ItsSecurityBaseComponent {
      if(not(f_loadCertificates(PX_IUT_SEC_CONFIG_NAME))) {
        log("*** INFO: TEST CASE NOW STOPPING ITSELF! ***");
        setverdict(inconc);
        stop;
      }
    } // End of function f_initialiseSecuredMode()
    
    function f_uninitialiseSecuredMode() runs on ItsSecurityBaseComponent {
      f_unloadCertificates();
    } // End of function f_uninitialiseSecuredMode()
    
    function f_initializeState() runs on ItsPkiItss {
      var Oct8 v_hashedId8ToBeUsed;

      log(">>> f_initializeState: vc_hashedId8ToBeUsed= ", vc_hashedId8ToBeUsed);
      v_hashedId8ToBeUsed := f_setupIutCertificate(vc_hashedId8ToBeUsed);
      log("f_initializeState: v_hashedId8ToBeUsed= ", v_hashedId8ToBeUsed);

      f_utInitializeIut(UtPkiInitialize: { v_hashedId8ToBeUsed } );

      f_sleep(PX_NEIGHBOUR_DISCOVERY_DELAY);
      
      //      f_acLoadScenario(p_scenario);
      //      f_acStartScenario();
    }
    
  } // End of pkiConfigurationFunctions

  group ut_port {

    function f_utInitializeIut(template (value) UtPkiInitialize p_init) runs on ItsPkiItss {
      utPort.send(p_init);
      tc_wait.start;
      alt {
        [] utPort.receive(UtPkiResults: { utPkiInitializeResult := true }) {
          tc_wait.stop;
          log("*** f_utInitializeIut: INFO: IUT initialized ***");
        }
        [] utPort.receive {
          tc_wait.stop;
          log("*** f_utInitializeIut: INFO: IUT could not be initialized ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
        [] tc_wait.timeout {
          log("*** f_utInitializeIut: INFO: IUT could not be initialized in time ***");
          f_selfOrClientSyncAndVerdict("error", e_timeout);
        }
      }
      
    } // End of function f_utInitializeIut
    
    function f_sendUtTriggerEnrolmentRequestPrimitive(
                                                      in octetstring p_canonical_id := ''O,
                                                      in Oct1 p_enc_algorithm := '00'O,
                                                      in octetstring p_private_key := ''O,
                                                      in octetstring p_public_key_compressed := ''O,
                                                      in integer p_compressed_mode := 0
                                                      ) runs on ItsPkiItss {
      var TriggerEnrolmentRequest v_ut_trigger_enrolment_request;
      var octetstring v_compressed_public_key;

      if (p_compressed_mode == 2) { // TODO v_compressed_public_key := int2oct(p_compressed_mode, 1) & p_public_key_compressed?
        v_compressed_public_key := '02'O & p_public_key_compressed;
      } else {
        v_compressed_public_key := '03'O & p_public_key_compressed;
      }
      
      v_ut_trigger_enrolment_request := { p_canonical_id, p_enc_algorithm, p_private_key, v_compressed_public_key };
      utPort.send(UtPkiTrigger: { triggerEnrolmentRequest := v_ut_trigger_enrolment_request });
      tc_ac.start;
      alt {
        [] utPort.receive(UtPkiResults: { utPkiTriggerResult := true }) {
          tc_ac.stop;
        }
        [] utPort.receive(UtPkiResults: { utPkiTriggerResult := false }) {
          tc_ac.stop;
          log("*** f_sendUtTriggerEnrolmentRequestPrimitive: ERROR: Received unexpected message ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
        [] tc_ac.timeout {
          log("*** f_sendAcPkiPrimitive: ERROR: Timeout while waiting for adapter control event result ***");
          f_selfOrClientSyncAndVerdict("error", e_timeout);
        }
      } // End of 'alt' statement
    } // End of function f_sendUtTriggerEnrolmentRequestPrimitive
    
    function f_sendUtTriggerAuthorizationRequestPrimitive(
                                                          in octetstring p_canonical_id := ''O,
                                                          in Oct1 p_enc_algorithm := '00'O,
                                                          in octetstring p_private_key := ''O,
                                                          in octetstring p_public_key_compressed := ''O,
                                                          in integer p_compressed_mode := 0
                                                          ) runs on ItsPkiItss {
      var TriggerAuthorizationRequest v_ut_trigger_enrolment_request;
      var octetstring v_compressed_public_key;

      if (p_compressed_mode == 2) { // TODO v_compressed_public_key := int2oct(p_compressed_mode, 1) & p_public_key_compressed?
        v_compressed_public_key := '02'O & p_public_key_compressed;
      } else {
        v_compressed_public_key := '03'O & p_public_key_compressed;
      }
      
      v_ut_trigger_enrolment_request := { p_canonical_id, p_enc_algorithm, p_private_key, v_compressed_public_key };
      utPort.send(UtPkiTrigger: { triggerAuthorizationRequest := v_ut_trigger_enrolment_request });
      tc_ac.start;
      alt {
        [] utPort.receive(UtPkiResults: { utPkiTriggerResult := true }) {
          tc_ac.stop;
        }
        [] utPort.receive(UtPkiResults: { utPkiTriggerResult := false }) {
          tc_ac.stop;
          log("*** f_sendUtTriggerAuthorizationRequestPrimitive: ERROR: Received unexpected message ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
        [] tc_ac.timeout {
          log("*** f_sendAcPkiPrimitive: ERROR: Timeout while waiting for adapter control event result ***");
          f_selfOrClientSyncAndVerdict("error", e_timeout);
        }
      } // End of 'alt' statement
    } // End of function f_sendUtTriggerAuthorizationRequestPrimitive
    
    function f_sendUtTriggerUpdateEctl(template (value) charstring p_ectl_uri) runs on ItsPkiItss {
      utPort.send(UtPkiTrigger: { triggerUpdateEctl := { ectl_uri := p_ectl_uri } });
      tc_wait.start;
      alt {
        [] utPort.receive(UtPkiResults: { utPkiTriggerResult := true }) {
          tc_wait.stop;
          log("*** f_sendUtTriggerUpdateEctl: INFO: IUT has updated ECTL ***");
        }
        [] utPort.receive {
          tc_wait.stop;
          log("*** f_sendUtTriggerUpdateEctl: INFO: IUT could not update ECTL ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
        [] tc_wait.timeout {
          log("*** f_sendUtTriggerUpdateEctl: INFO: IUT could not update ECTL in time ***");
          f_selfOrClientSyncAndVerdict("error", e_timeout);
        }
      }
      
    } // End of function f_sendUtTriggerUpdateEctl
    
    function f_sendUtTriggerRequestForTlmCtl(template (value) charstring p_tlm_ctl_uri) runs on ItsPkiItss {
      utPort.send(UtPkiTrigger: { triggerRequestForTlmCtl := { tlm_ctl_uri := p_tlm_ctl_uri } });
      tc_wait.start;
      alt {
        [] utPort.receive(UtPkiResults: { utPkiTriggerResult := true }) {
          tc_wait.stop;
          log("*** f_sendUtTriggerRequestForTlmCtl: INFO: IUT has updated ECTL ***");
        }
        [] utPort.receive {
          tc_wait.stop;
          log("*** f_sendUtTriggerRequestForTlmCtl: INFO: IUT could not update ECTL ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
        [] tc_wait.timeout {
          log("*** f_sendUtTriggerRequestForTlmCtl: INFO: IUT could not update ECTL in time ***");
          f_selfOrClientSyncAndVerdict("error", e_timeout);
        }
      }
      
    } // End of function f_sendUtTriggerRequestForTlmCtl
    
    function f_sendUtTriggerRequestForRcaCtl(template (value) charstring p_tlm_ctl_uri) runs on ItsPkiItss {
      utPort.send(UtPkiTrigger: { triggerRequestForRcaCtl := { tlm_ctl_uri := p_tlm_ctl_uri } });
      tc_wait.start;
      alt {
        [] utPort.receive(UtPkiResults: { utPkiTriggerResult := true }) {
          tc_wait.stop;
          log("*** f_sendUtTriggerRequestForRcaCtl: INFO: IUT has updated ECTL ***");
        }
        [] utPort.receive {
          tc_wait.stop;
          log("*** f_sendUtTriggerRequestForRcaCtl: INFO: IUT could not update ECTL ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
        [] tc_wait.timeout {
          log("*** f_sendUtTriggerRequestForRcaCtl: INFO: IUT could not update ECTL in time ***");
          f_selfOrClientSyncAndVerdict("error", e_timeout);
        }
      }
      
    } // End of function f_sendUtTriggerRequestForRcaCtl
    
ASN.1 Documenter's avatar
ASN.1 Documenter committed
  } // End of group ut_port

  group helpers {

    function f_generate_key_pair(
                                 out octetstring p_private_key,
                                 out octetstring p_public_key_x,
                                 out octetstring p_public_key_y,
                                 out octetstring p_public_key_compressed,
                                 out integer p_compressed_mode
                                 ) return boolean {
      log(">>> f_generate_key_pair: PX_VE_ALG=", PX_VE_ALG);
      
      if (PX_VE_ALG == e_nist_p256) {
        f_generate_key_pair_nistp256(p_private_key, p_public_key_x, p_public_key_y, p_public_key_compressed, p_compressed_mode);
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        f_generate_key_pair_brainpoolp256r1(p_private_key, p_public_key_x, p_public_key_y, p_public_key_compressed, p_compressed_mode);
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        f_generate_key_pair_brainpoolp384r1(p_private_key, p_public_key_x, p_public_key_y, p_public_key_compressed, p_compressed_mode);
      } else {
        // error
        return false;
      }

      log("<<< f_generate_key_pair: p_compressed_mode=", p_compressed_mode);
      return true;
    }

    function f_generate_key_pair_for_encryption(
                                                in SignAlgorithm p_algorithm,
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                out octetstring p_private_key,
                                                out octetstring p_public_key_x,
                                                out octetstring p_public_key_y,
                                                out octetstring p_public_key_compressed,
                                                out integer p_compressed_mode
                                                ) return boolean {
      if (p_algorithm == e_nist_p256) {
        f_generate_key_pair_nistp256(p_private_key, p_public_key_x, p_public_key_y, p_public_key_compressed, p_compressed_mode);
      } else if (p_algorithm == e_brainpool_p256_r1) {
        f_generate_key_pair_brainpoolp256r1(p_private_key, p_public_key_x, p_public_key_y, p_public_key_compressed, p_compressed_mode);
      } else {
        // error
        return false;
      }

      return true;
    }

    function f_http_send(
                         in Headers p_headers,
                         in template (value) HttpMessage p_http_message
                         ) runs on ItsPkiHttp {
      log(">>> f_http_send: ", p_http_message);
      
      if (not(PICS_MULTIPLE_END_POINT)) {
        httpPort.send(p_http_message);
      } else {
        var charstring_list v_content_text;
        
        f_get_header(p_headers, c_header_content_text, v_content_text);
        
        if (not(isvalue(v_content_text))) {
          log("f_http_send: Failed to send message: header not found: ", c_header_content_text);
          return;
        }
        if (v_content_text == { "inner_ec_request" }) {
          log("f_http_send: Send on EC end point");
          f_set_headers_list({ c_header_host }, { PICS_HEADER_HOST_EC }, p_headers);
          if (ischosen(p_http_message.request)) {
            p_http_message.request.header := p_headers;
          } else {
            p_http_message.response.header := p_headers;
          }
          httpEcPort.send(p_http_message);
        } else if (v_content_text == { "inner_atv_request" }) {
          log("f_http_send: Send on ATV end point");
          f_set_headers_list({ c_header_host }, { PICS_HEADER_HOST_ATV }, p_headers);
          if (ischosen(p_http_message.request)) {
            p_http_message.request.header := p_headers;
          } else {
            p_http_message.response.header := p_headers;
          }
          httpAtVPort.send(p_http_message);
        } else if (v_content_text == { "inner_atv_response" }) {
          log("f_http_send: Send on ATV end point");
          f_set_headers_list({ c_header_host }, { PICS_HEADER_HOST_ATV }, p_headers);
          if (ischosen(p_http_message.request)) {
            p_http_message.request.header := p_headers;
          } else {
            p_http_message.response.header := p_headers;
          }
          httpAtVPort.send(p_http_message);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        } else if (v_content_text == { "inner_at_request" }) {
          log("f_http_send: Send on AT end point");
          f_set_headers_list({ c_header_host }, { PICS_HEADER_HOST_AT }, p_headers);
          if (ischosen(p_http_message.request)) {
            p_http_message.request.header := p_headers;
          } else {
            p_http_message.response.header := p_headers;
          }
          httpAtPort.send(p_http_message);
        } else if (v_content_text == { "ca_request" }) {
          log("f_http_send: Send on CA end point");
          f_set_headers_list({ c_header_host }, { PICS_HEADER_HOST_CA }, p_headers);
          if (ischosen(p_http_message.request)) {
            p_http_message.request.header := p_headers;
          } else {
            p_http_message.response.header := p_headers;
          }
          httpCaPort.send(p_http_message);
        } else if (v_content_text == { "ca_response" }) {
          log("f_http_send: Send on CA end point");
          f_set_headers_list({ c_header_host }, { PICS_HEADER_HOST_CA }, p_headers);
          if (ischosen(p_http_message.request)) {
            p_http_message.request.header := p_headers;
          } else {
            p_http_message.response.header := p_headers;
          }
          httpCaPort.send(p_http_message);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        } else if (v_content_text == { "tlm_request" }) {
          log("f_http_send: Send on TLM end point");
          f_set_headers_list({ c_header_host }, { PICS_HEADER_HOST_TLM }, p_headers);
          if (ischosen(p_http_message.request)) {
            p_http_message.request.header := p_headers;
          } else {
            p_http_message.response.header := p_headers;
          }
          httpTlmPort.send(p_http_message);
        } else {
          log("f_http_send: Invalid header value: ", v_content_text);
        }
      }
    } // End of function f_http_send

    function f_generate_key_tag(
                                in octetstring p_public_key_compressed,
                                in integer p_compressed_key_mode,
                                in octetstring p_public_compressed_enc_key,
                                in integer p_compressed_enc_key_mode,
                                out octetstring p_encoded_tag
                                ) return boolean {
      // Local variables
      var PublicVerificationKey v_verification_tag;
      var PublicEncryptionKey v_encryption_tag;

      log(">>> f_generate_key_tag: p_public_key_compressed=", p_public_key_compressed);
      log(">>> f_generate_key_tag: p_public_compressed_enc_key=", p_public_compressed_enc_key);
      
      
      if (PX_VE_ALG == e_nist_p256) {
        if (p_compressed_key_mode == 0) {
          v_verification_tag.ecdsaNistP256.compressed_y_0 := p_public_key_compressed;
        } else {
          v_verification_tag.ecdsaNistP256.compressed_y_1 := p_public_key_compressed;
        }
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        if (p_compressed_key_mode == 0) {
          v_verification_tag.ecdsaBrainpoolP256r1.compressed_y_0 := p_public_key_compressed;
        } else {
          v_verification_tag.ecdsaBrainpoolP256r1.compressed_y_1 := p_public_key_compressed;
        }
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        if (p_compressed_key_mode == 0) {
          v_verification_tag.ecdsaBrainpoolP384r1.compressed_y_0 := p_public_key_compressed;
        } else {
          v_verification_tag.ecdsaBrainpoolP384r1.compressed_y_1 := p_public_key_compressed;
        }
      } else {
        log("f_generate_key_tag: Failed to generate HMAC tag");
        return false;
      }
      log("f_generate_key_tag: v_verification_tag= ", v_verification_tag);
      p_encoded_tag := bit2oct(encvalue(v_verification_tag));
      if (PX_INCLUDE_ENCRYPTION_KEYS) {
        v_encryption_tag.supportedSymmAlg := aes128Ccm;
        if (PX_EC_ALG_FOR_EC_SIGN == e_nist_p256) {
          if (p_compressed_enc_key_mode == 0) {
            v_encryption_tag.publicKey.eciesNistP256.compressed_y_0 := p_public_compressed_enc_key;
          } else {
            v_encryption_tag.publicKey.eciesNistP256.compressed_y_1 := p_public_compressed_enc_key;
          }
        } else if (PX_EC_ALG_FOR_EC_SIGN == e_brainpool_p256_r1) {
          if (p_compressed_enc_key_mode == 0) {
            v_encryption_tag.publicKey.eciesBrainpoolP256r1.compressed_y_0 := p_public_compressed_enc_key;
          } else {
            v_encryption_tag.publicKey.eciesBrainpoolP256r1.compressed_y_1 := p_public_compressed_enc_key;
          }
        } else {
          log("f_generate_key_tag: Failed to generate HMAC tag (enc)");
          return false;
        }
        log("f_generate_key_tag: v_encryption_tag= ", v_encryption_tag);
        p_encoded_tag := p_encoded_tag & bit2oct(encvalue(v_encryption_tag));
      }

      return true;
    } // End of function f_generate_key_tag
    
  } // End of group helpers
  
  group http { // TODO Split into EnnerEc, Authorization & AuthorizationValidation

    function f_http_build_inner_ec_request( // TODO Cleanup parameters
                                           out octetstring p_private_key,
                                           out octetstring p_public_key_compressed,
                                           out integer p_compressed_mode,
                                           out Oct16 p_aes_sym_key,
                                           out Oct16 p_encrypted_sym_key,
                                           out Oct16 p_authentication_vector,
                                           out Oct12 p_nonce,
                                           out octetstring p_salt,
                                           out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                           out Oct32 p_request_hash
                                           ) runs on ItsPkiHttp {
      var InnerEcRequest v_inner_ec_request;
      var Ieee1609Dot2Data v_inner_ec_request_signed_for_pop;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;
      var boolean v_result;

      log(">>> f_http_build_inner_ec_request");
      log ("f_http_build_inner_ec_request: vc_ec_keys_counter: ", vc_ec_keys_counter);
      log ("f_http_build_inner_ec_request: vc_ec_private_keys: ", vc_ec_private_keys);
      log ("f_http_build_inner_ec_request: vc_ec_counter: ", vc_ec_counter);

ASN.1 Documenter's avatar
ASN.1 Documenter committed
      if (f_generate_inner_ec_request(p_private_key, p_public_key_compressed, p_compressed_mode, v_inner_ec_request) == false) {
        log("*** f_http_build_inner_ec_request: ERROR: Failed to generate InnerEcRequest ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log ("f_http_build_inner_ec_request: ==> EC verification private key: ", p_private_key);
      log ("f_http_build_inner_ec_request: ==> EC verification public compressed key: ", p_public_key_compressed);
      log ("f_http_build_inner_ec_request: ==> EC verification public compressed mode: ", p_compressed_mode);
      // TODO Store enrolment keys for re-enrolment
      vc_ec_private_keys[vc_ec_keys_counter] := p_private_key;
      vc_ec_public_compressed_key[vc_ec_keys_counter] := p_public_key_compressed;
      vc_ec_compressed_modes[vc_ec_keys_counter] := p_compressed_mode;
      vc_ec_keys_counter := vc_ec_keys_counter + 1;
      // Generate InnerEcRequestSignedForPoP
      if (f_generate_inner_ec_request_signed_for_pop(p_private_key, v_inner_ec_request, v_inner_ec_request_signed_for_pop) == false) {
        log("*** f_http_build_inner_ec_request: ERROR: Failed to generate InnerEcRequestSignedForPop ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_inner_ec_request: v_inner_ec_request_signed_for_pop= ", v_inner_ec_request_signed_for_pop);
      
      // Secure InnerEcRequestSignedForPoP message
      if (f_extract_enc_key(vc_eaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("*** f_http_build_inner_ec_request: ERROR: Non canonical EA certificate ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_inner_ec_request: Public encryption key: ", v_public_enc_key);
      log("f_http_build_inner_ec_request: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_eaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      log("f_http_build_inner_ec_request: vc_ec_keys_counter: ", vc_ec_keys_counter);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      if ((PICS_SECPKI_REENROLMENT == false) or (vc_ec_keys_counter == 1)) { // This is the first enrolment, we used Factory keys
        var octetstring v_private_key;
        if (PX_VE_ALG == e_nist_p256) {
          v_private_key := PICS_ITS_S_SIGN_NITSP256_PRIVATE_KEY;
        } else if (PX_VE_ALG == e_brainpool_p256_r1) {
          v_private_key := PICS_ITS_S_SIGN_BRAINPOOLP256r1_PRIVATE_KEY;
        } else {
          v_private_key := PICS_ITS_S_SIGN_BRAINPOOLP384r1_PRIVATE_KEY;
        }
        v_result := f_build_pki_secured_request_message_signed_with_pop(v_private_key, valueof(m_signerIdentifier_self), vc_eaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_inner_ec_request_signed_for_pop(v_inner_ec_request_signed_for_pop))), PX_EC_ALG_FOR_EC, -, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash);
      } else { // We use last valid EC certificate
        // TODO Retrieve EC certificate from the first enrolment instead of PX
        log("f_http_build_inner_ec_request: v_ec_private_key: ", vc_ec_private_keys[vc_ec_keys_counter - 1]);
        log("f_http_build_inner_ec_request: v_ec_public_compressed_key: ", vc_ec_public_compressed_key[vc_ec_keys_counter - 1]);
        log("f_http_build_inner_ec_request: v_ec_compressed_modes: ", vc_ec_compressed_modes[vc_ec_keys_counter - 1]);
        log("f_http_build_inner_ec_request: v_ec_hashed_id8: ", vc_ec_hashed_id8[vc_ec_keys_counter - 1]);
        v_result := f_build_pki_secured_request_message_signed_with_pop(vc_ec_private_keys[vc_ec_keys_counter - 1], valueof(m_signerIdentifier_digest(vc_ec_hashed_id8[vc_ec_keys_counter - 1])), vc_ec_hashed_id8[vc_ec_keys_counter - 1]/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_inner_ec_request_signed_for_pop(v_inner_ec_request_signed_for_pop))), PX_EC_ALG_FOR_EC, -, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      }
      if (v_result == false) {
        log("*** f_http_build_inner_ec_request: ERROR: Failed to generate InnerEcRequestSignedForPop ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      } else {
        log("f_http_build_inner_ec_request: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data);
        log("f_http_build_inner_ec_request: p_request_hash= ", p_request_hash);
      }
    } // End of function f_http_build_inner_ec_request

    function f_http_build_inner_ec_request_with_wrong_parameters( // TODO Cleanup parameters
                                                                 in SequenceOfPsidSsp p_appPermissions,
                                                                 in octetstring p_canonical_id := PICS_ITS_S_CANONICAL_ID,
                                                                 in Time32 p_start,
                                                                 in Duration p_duration,
                                                                 in boolean p_alter_private_key := false,
                                                                 out octetstring p_private_key,
                                                                 out octetstring p_public_key_compressed,
                                                                 out integer p_compressed_mode,
                                                                 out Oct16 p_aes_sym_key,
                                                                 out Oct16 p_encrypted_sym_key,
                                                                 out Oct16 p_authentication_vector,
                                                                 out Oct12 p_nonce,
                                                                 out octetstring p_salt,
                                                                 out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                                 out Oct32 p_request_hash
                                                                 ) runs on ItsPkiHttp {
      var InnerEcRequest v_inner_ec_request;
      var Ieee1609Dot2Data v_inner_ec_request_signed_for_pop;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;
      var boolean v_result;

      log(">>> f_http_build_inner_ec_request_with_wrong_parameters");
      if (f_generate_inner_ec_request_with_wrong_parameters(p_appPermissions, p_canonical_id, p_start, p_duration, p_alter_private_key, p_private_key, p_public_key_compressed, p_compressed_mode, v_inner_ec_request) == false) {
        log("*** f_http_build_inner_ec_request_with_wrong_parameters: ERROR: Failed to generate InnerEcRequest ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log ("f_http_build_inner_ec_request_with_wrong_parameters: ==> EC verification private key: ", p_private_key);
      log ("f_http_build_inner_ec_request_with_wrong_parameters: ==> EC verification public compressed key: ", p_public_key_compressed);
      log ("f_http_build_inner_ec_request_with_wrong_parameters: ==> EC verification public compressed mode: ", p_compressed_mode);
      // Generate InnerEcRequestSignedForPoP
      if (f_generate_inner_ec_request_signed_for_pop(p_private_key, v_inner_ec_request, v_inner_ec_request_signed_for_pop) == false) {
        log("*** f_http_build_inner_ec_request_with_wrong_parameters: ERROR: Failed to generate InnerEcRequestSignedForPop ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_inner_ec_request_with_wrong_parameters: v_inner_ec_request_signed_for_pop= ", v_inner_ec_request_signed_for_pop);
      
      // Secure InnerEcRequestSignedForPoP message
      if (f_extract_enc_key(vc_eaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("*** f_http_build_inner_ec_request_with_wrong_parameters: ERROR: Non canonical EA certificate ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_inner_ec_request_with_wrong_parameters: Public encryption key: ", v_public_enc_key);
      log("f_http_build_inner_ec_request_with_wrong_parameters: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_eaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      var octetstring v_private_key;
      if (PX_VE_ALG == e_nist_p256) {
        v_private_key := PICS_ITS_S_SIGN_NITSP256_PRIVATE_KEY;
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        v_private_key := PICS_ITS_S_SIGN_BRAINPOOLP256r1_PRIVATE_KEY;
      } else {
        v_private_key := PICS_ITS_S_SIGN_BRAINPOOLP384r1_PRIVATE_KEY;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      }
      v_result := f_build_pki_secured_request_message_signed_with_pop(v_private_key, valueof(m_signerIdentifier_self), vc_eaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_inner_ec_request_signed_for_pop(v_inner_ec_request_signed_for_pop))), PX_EC_ALG_FOR_EC, -, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      if (v_result == false) {
        log("*** f_http_build_inner_ec_request_with_wrong_parameters: ERROR: Failed to generate InnerEcRequestSignedForPop ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      } else {
        log("f_http_build_inner_ec_request_with_wrong_parameters: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data);
        log("f_http_build_inner_ec_request_with_wrong_parameters: p_request_hash= ", p_request_hash);
      }
    } // End of function f_http_build_inner_ec_request_with_wrong_parameters

    function f_http_build_invalid_enrolment_request(
                                                    out octetstring p_private_key,
                                                    out octetstring p_public_key_compressed,
                                                    out integer p_compressed_mode,
                                                    out Oct16 p_aes_sym_key,
                                                    out Oct16 p_encrypted_sym_key,
                                                    out Oct16 p_authentication_vector,
                                                    out Oct12 p_nonce,
                                                    out octetstring p_salt,
                                                    out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                    out Oct32 p_request_hash
                                                    ) runs on ItsPkiHttp {
      var InnerEcRequest v_inner_ec_request;
      var Ieee1609Dot2Data v_inner_ec_request_signed_for_pop;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;
      var boolean v_ret_code;
      var octetstring v_private_key;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      
      if (f_generate_inner_ec_request(p_private_key, p_public_key_compressed, p_compressed_mode, v_inner_ec_request) == false) {
        log("*** f_http_build_invalid_enrolment_request: ERROR: Failed to generate InnerEcRequest ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log ("f_http_build_invalid_enrolment_request: EC verification private key: ", p_private_key);
      log ("f_http_build_invalid_enrolment_request: EC verification public compressed key: ", p_public_key_compressed);
      log ("f_http_build_invalid_enrolment_request: EC verification public compressed mode: ", p_compressed_mode);
      // Generate InnerEcRequestSignedForPoP
      if (f_generate_inner_ec_request_signed_for_pop(p_private_key, v_inner_ec_request, v_inner_ec_request_signed_for_pop) == false) {
        log("*** f_http_build_invalid_enrolment_request: ERROR: Failed to generate InnerEcRequestSignedForPop ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_invalid_enrolment_request: v_inner_ec_request_signed_for_pop= ", v_inner_ec_request_signed_for_pop);
      // Modify signature to get an error
      if (ischosen(v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaNistP256Signature)) {
        v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaNistP256Signature.sSig[1] := bit2oct('10101010'B xor4b oct2bit(v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaNistP256Signature.sSig[1]));
      } else if (ischosen(v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaBrainpoolP256r1Signature)) {
        v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaBrainpoolP256r1Signature.sSig[1] := bit2oct('10101010'B xor4b oct2bit(v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaBrainpoolP256r1Signature.sSig[1]));
      } else {
        v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaBrainpoolP384r1Signature.sSig[1] := bit2oct('10101010'B xor4b oct2bit(v_inner_ec_request_signed_for_pop.content.signedData.signature_.ecdsaBrainpoolP384r1Signature.sSig[1]));
      }
      
      // Secure InnerEcRequestSignedForPoP message
      if (f_extract_enc_key(vc_eaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("*** f_http_build_invalid_enrolment_request: ERROR: Non canonical EA certificate ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("*** f_http_build_invalid_enrolment_request: Public encryption key: ", v_public_enc_key);
      log("*** f_http_build_invalid_enrolment_request: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_eaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      if (PX_VE_ALG == e_nist_p256) {
        v_private_key := PICS_ITS_S_SIGN_NITSP256_PRIVATE_KEY;
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        v_private_key := PICS_ITS_S_SIGN_BRAINPOOLP256r1_PRIVATE_KEY;
      } else {
        v_private_key := PICS_ITS_S_SIGN_BRAINPOOLP384r1_PRIVATE_KEY;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      }
      v_ret_code := f_build_pki_secured_request_message_signed_with_pop(v_private_key, valueof(m_signerIdentifier_self), vc_eaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_inner_ec_request_signed_for_pop(v_inner_ec_request_signed_for_pop))), PX_EC_ALG_FOR_EC, -, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      if (v_ret_code == false) {
        log("*** f_http_build_invalid_enrolment_request: ERROR: Failed to generate InnerEcRequestSignedForPop ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("*** f_http_build_invalid_enrolment_request: DEBUG: p_ieee1609dot2_signed_and_encrypted_data = ", p_ieee1609dot2_signed_and_encrypted_data);
    } // End of function f_http_build_invalid_enrolment_request

    function f_http_build_inner_ec_response(
                                            in template (omit) InnerEcRequest p_inner_ec_request := omit,
                                            in EnrolmentResponseCode p_responseCode := ok,
                                            in Oct16 p_request_hash,
                                            in octetstring p_private_key := ''O,
                                            in octetstring p_digest := ''O,
                                            in Oct16 p_aes_sym_key,
                                            out EtsiTs103097Certificate p_ec_certificate,
                                            out HashedId8 p_ec_certificate_hashed_id8,
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                            out InnerEcResponse p_inner_ec_response,
                                            out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data
                                            ) return boolean {
      // Local variables
      var bitstring v_msg_bit;
      var octetstring v_msg;
      var Oct12 v_nonce;
      var Ieee1609Dot2Data v_ieee1609dot2_signed_data;
      var boolean p_result := false;

      log(">>> f_http_build_inner_ec_response: p_inner_ec_request= ", p_inner_ec_request);
      log(">>> f_http_build_inner_ec_response: p_responseCode= ", p_responseCode);
      log(">>> f_http_build_inner_ec_response: p_request_hash= ", p_request_hash);
      log(">>> f_http_build_inner_ec_response: p_private_key= ", p_private_key);
      log(">>> f_http_build_inner_ec_response: p_digest= ", p_digest);
      log(">>> f_http_build_inner_ec_response: p_aes_sym_key= ", p_aes_sym_key);
      
      // Check expectred response
      if (p_responseCode != ok) {
        p_inner_ec_response := valueof(
                                       m_innerEcResponse_ko(
                                                            p_request_hash,
                                                            p_responseCode
                                                            )
                                       );
        p_result := true;
      } else {
        // Generate the certificate
        if (f_generate_ec_certificate_for_inner_ec_response(valueof(p_inner_ec_request), p_private_key, p_digest, p_ec_certificate, p_ec_certificate_hashed_id8) == false) {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
          log("f_http_build_inner_ec_response: Failed to generate the certificate");
          p_inner_ec_response := valueof(
                                         m_innerEcResponse_ko(
                                                              p_request_hash,
                                                              incompleterequest
                                                              )
                                         );
        } else {
          p_inner_ec_response := valueof(
                                         m_innerEcResponse_ok(
                                                              p_request_hash,
                                                              p_ec_certificate
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                              )
                                         );
        }
      }

      // Secure the response
      log("f_http_build_inner_ec_response: p_inner_ec_response= ", p_inner_ec_response);
      v_msg := bit2oct(encvalue(m_etsiTs102941Data_inner_ec_response(p_inner_ec_response)));
      v_nonce := substr(f_hashWithSha256(int2oct((f_getCurrentTimeUtc() * 1000), 16)), 0, 12); // Random value
      // TODO Consider  Sha384: m_signerIdentifier_digest(f_hashedId8FromSha384(p_digest))
      if (f_build_pki_secured_response_message(p_private_key,
                                               valueof(m_signerIdentifier_digest(f_hashedId8FromSha256(p_digest))),//  in SignerIdentifier p_signer_identifier,
                                               v_msg,
                                               p_aes_sym_key,
                                               v_nonce,
                                               p_ieee1609dot2_signed_and_encrypted_data
                                               ) == false) {
        log("f_http_build_inner_ec_response: Failed to generate the certificate");
        p_inner_ec_response := valueof(
                                       m_innerEcResponse_ko(
                                                            p_request_hash,
                                                            deniedrequest
                                                            )
                                       );
      } else {
        p_result := true;
      }

      return p_result;
    } // End of function f_http_build_inner_ec_response
    
    function f_http_build_authorization_request(
                                                in Certificate p_ec_certificate, // Enrolment credentials certificate
                                                in octetstring p_ec_private_key,
                                                out octetstring p_private_key,
                                                out octetstring p_public_key_compressed,
                                                out integer p_compressed_key_mode,
                                                out octetstring p_private_enc_key,
                                                out octetstring p_public_compressed_enc_key,
                                                out integer p_compressed_enc_key_mode,
                                                out Oct16 p_aes_sym_key,
                                                out Oct16 p_encrypted_sym_key,
                                                out Oct16 p_authentication_vector,
                                                out Oct12 p_nonce,
                                                out octetstring p_salt,
                                                out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                out Oct32 p_request_hash
                                                ) runs on ItsPkiHttp {
      // Local variables
      var octetstring v_public_key_x;
      var octetstring v_public_key_y;
      var octetstring v_public_enc_key_x;
      var octetstring v_public_enc_key_y;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;
      var InnerAtRequest v_inner_at_request;
      var Ieee1609Dot2Data v_inner_at_request_data;
      var InnerAtRequest v_authorization_request;
      var bitstring v_authorization_request_msg;

      // Generate the InnerAtRequest
      if (f_generate_inner_at_request(vc_aaCertificate, -, vc_aaHashedId8, vc_eaCertificate, vc_eaWholeHash/*salt*/, vc_eaHashedId8, p_ec_certificate, p_ec_private_key, p_private_key, p_public_key_compressed, p_compressed_key_mode, p_private_enc_key, p_public_compressed_enc_key, p_compressed_enc_key_mode, v_inner_at_request) == false) {
        log("*** f_http_build_authorization_request: ERROR: Failed to generate AuthorizationRequest ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
        return;
      }
      log("f_http_build_authorization_request: v_inner_at_request= ", v_inner_at_request);
      
      // Secure InnerAtRequest message
      if (f_extract_enc_key(vc_aaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("*** f_http_build_authorization_request: ERROR: Non canonical AA certificate ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("*** f_http_build_authorization_request: Public encryption key: ", v_public_enc_key);
      log("*** f_http_build_authorization_request: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_aaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      log("*** f_http_build_authorization_request: p_salt: ", p_salt);
      if (PICS_PKI_AUTH_POP) {
        if(f_build_pki_secured_request_message_signed_with_pop(p_private_key, valueof(m_signerIdentifier_self), vc_aaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_request(v_inner_at_request))), PX_EC_ALG_FOR_AT, -, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
          log("*** f_http_build_authorization_request: ERROR: Failed to generate Authorization Request ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
      } else { // Only encryption of EtsiTs102941Data/InnerAtRequest
        log("*** f_http_build_authorization_request: POP signature not applied");
        if(f_build_pki_secured_request_message_for_authorization(vc_aaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_request(v_inner_at_request))), PX_EC_ALG_FOR_AT, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
          log("*** f_http_build_authorization_request: ERROR: Failed to generate Authorization Request ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
      }
      log("<<< f_http_build_authorization_request: DEBUG: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data);
      log("<<< f_http_build_authorization_request: DEBUG: p_request_hash= ", p_request_hash);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
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 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617
    } // End of function f_http_build_authorization_request

    function f_http_build_authorization_request_with_wrong_private_key(
                                                                       in Certificate p_ec_certificate, // Enrolment credentials certificate
                                                                       in octetstring p_ec_private_key,
                                                                       out octetstring p_private_key,
                                                                       out octetstring p_public_key_compressed,
                                                                       out integer p_compressed_key_mode,
                                                                       out octetstring p_private_enc_key,
                                                                       out octetstring p_public_compressed_enc_key,
                                                                       out integer p_compressed_enc_key_mode,
                                                                       out Oct16 p_aes_sym_key,
                                                                       out Oct16 p_encrypted_sym_key,
                                                                       out Oct16 p_authentication_vector,
                                                                       out Oct12 p_nonce,
                                                                       out octetstring p_salt,
                                                                       out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                                       out Oct32 p_request_hash
                                                                       ) runs on ItsPkiHttp {
      // Local variables
      var octetstring v_public_key_x;
      var octetstring v_public_key_y;
      var octetstring v_public_enc_key_x;
      var octetstring v_public_enc_key_y;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;
      var InnerAtRequest v_inner_at_request;
      var Ieee1609Dot2Data v_inner_at_request_data;
      var InnerAtRequest v_authorization_request;
      var bitstring v_authorization_request_msg;

      // Generate the InnerAtRequest
      if (f_generate_inner_at_request(vc_aaCertificate, -, vc_aaHashedId8, vc_eaCertificate, vc_eaWholeHash/*salt*/, vc_eaHashedId8, p_ec_certificate, p_ec_private_key, p_private_key, p_public_key_compressed, p_compressed_key_mode, p_private_enc_key, p_public_compressed_enc_key, p_compressed_enc_key_mode, v_inner_at_request) == false) {
        log("*** f_http_build_authorization_request_with_wrong_private_key: ERROR: Failed to generate AuthorizationRequest ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
        return;
      }
      log("f_http_build_authorization_request_with_wrong_private_key: v_inner_at_request= ", v_inner_at_request);
      
      // Secure InnerAtRequest message
      /***
          Use the wrong private key
      ***/
      if (f_extract_enc_key(vc_eaCertificate/*Insted of vc_aaCertificate/*/, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("*** f_http_build_authorization_request_with_wrong_private_key: ERROR: Non canonical EA certificate ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("*** f_http_build_authorization_request_with_wrong_private_key: Public encryption key: ", v_public_enc_key);
      log("*** f_http_build_authorization_request_with_wrong_private_key: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_aaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      log("*** f_http_build_authorization_request_with_wrong_private_key: p_salt: ", p_salt);
      if (PICS_PKI_AUTH_POP) {
        if(f_build_pki_secured_request_message_signed_with_pop(p_private_key, valueof(m_signerIdentifier_self), vc_aaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_request(v_inner_at_request))), PX_EC_ALG_FOR_AT, -, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
          log("*** f_http_build_authorization_request_with_wrong_private_key: ERROR: Failed to generate Authorization Request ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
      } else { // Only encryption of EtsiTs102941Data/InnerAtRequest
        log("*** f_http_build_authorization_request_with_wrong_private_key: POP signature not applied");
        if(f_build_pki_secured_request_message_for_authorization(vc_aaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_request(v_inner_at_request))), PX_EC_ALG_FOR_AT, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
          log("*** f_http_build_authorization_request_with_wrong_private_key: ERROR: Failed to generate Authorization Request ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
      }
      log("*** f_http_build_authorization_request_with_wrong_private_key: DEBUG: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data);
      log("*** f_http_build_authorization_request_with_wrong_private_key: DEBUG: p_request_hash= ", p_request_hash);
    } // End of function f_http_build_authorization_request_with_wrong_private_key

    function f_http_build_authorization_request_with_wrong_parameters(
                                                                      in Certificate p_ec_certificate, // Enrolment credentials certificate
                                                                      in octetstring p_ec_private_key,
                                                                      in boolean p_alter_pop_signature := false,
                                                                      in boolean p_alter_hmac := false,
                                                                      in boolean p_alter_signer_digest := false,
                                                                      in boolean p_alter_pks_recipient := false,
                                                                      in boolean p_alter_enc_key := false,
                                                                      in boolean p_alter_ea_id := false,
                                                                      in template (omit) Time32 p_start := omit,
                                                                      in template (omit) Duration p_duration := omit,
                                                                      in template (omit) Time64 p_generation_time := omit,
                                                                      out octetstring p_private_key,
                                                                      out octetstring p_public_key_compressed,
                                                                      out integer p_compressed_key_mode,
                                                                      out octetstring p_private_enc_key,
                                                                      out octetstring p_public_compressed_enc_key,
                                                                      out integer p_compressed_enc_key_mode,
                                                                      out Oct16 p_aes_sym_key,
                                                                      out Oct16 p_encrypted_sym_key,
                                                                      out Oct16 p_authentication_vector,
                                                                      out Oct12 p_nonce,
                                                                      out octetstring p_salt,
                                                                      out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                                      out Oct32 p_request_hash
                                                                      ) runs on ItsPkiHttp {
      // Local variables
      var octetstring v_public_key_x;
      var octetstring v_public_key_y;
      var octetstring v_public_enc_key_x;
      var octetstring v_public_enc_key_y;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;
      var InnerAtRequest v_inner_at_request;
      var Ieee1609Dot2Data v_inner_at_request_data;
      var InnerAtRequest v_authorization_request;
      var bitstring v_authorization_request_msg;
      var boolean v_ret_code;

      // Generate the InnerAtRequest
      if (p_alter_ea_id == true) {
        var HashedId8 v_ea_hashed_id8 := vc_eaHashedId8;
        v_ea_hashed_id8[0] := 'bb'O;
        v_ea_hashed_id8[1] := 'cc'O;
        log("f_http_build_authorization_request_with_wrong_parameters: Altered eaId= ", v_ea_hashed_id8);
        v_ret_code := f_generate_inner_at_request(vc_aaCertificate, -, vc_aaHashedId8, vc_eaCertificate, vc_eaWholeHash/*salt*/, v_ea_hashed_id8, p_ec_certificate, p_ec_private_key, p_private_key, p_public_key_compressed, p_compressed_key_mode, p_private_enc_key, p_public_compressed_enc_key, p_compressed_enc_key_mode, v_inner_at_request);
      } else {
        v_ret_code := f_generate_inner_at_request_with_wrong_parameters(vc_aaCertificate, -, vc_aaHashedId8, vc_eaCertificate, vc_eaWholeHash/*salt*/, vc_eaHashedId8, p_ec_certificate, p_ec_private_key, p_alter_hmac, p_alter_signer_digest, p_start, p_duration, p_generation_time, p_private_key, p_public_key_compressed, p_compressed_key_mode, p_private_enc_key, p_public_compressed_enc_key, p_compressed_enc_key_mode, v_inner_at_request);
      }
      if (v_ret_code == false) {
        log("*** f_http_build_authorization_request_with_wrong_parameters: ERROR: Failed to generate AuthorizationRequest ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
        return;
      }
      log("f_http_build_authorization_request_with_wrong_parameters: v_inner_at_request= ", v_inner_at_request);
      
      // Secure InnerAtRequest message
      if (f_extract_enc_key(vc_aaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("*** f_http_build_authorization_request_with_wrong_parameters: ERROR: Non canonical AA certificate ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("*** f_http_build_authorization_request_with_wrong_parameters: Public encryption key: ", v_public_enc_key);
      log("*** f_http_build_authorization_request_with_wrong_parameters: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_aaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      log("*** f_http_build_authorization_request_with_wrong_parameters: p_salt: ", p_salt);
      if (PICS_PKI_AUTH_POP) {
        if(f_build_pki_secured_request_message_signed_with_pop(p_private_key, valueof(m_signerIdentifier_self), vc_aaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_request(v_inner_at_request))), PX_EC_ALG_FOR_AT, p_alter_pop_signature, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
          log("*** f_http_build_authorization_request_with_wrong_parameters: ERROR: Failed to generate Authorization Request ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
      } else { // Only encryption of EtsiTs102941Data/InnerAtRequest
        log("*** f_http_build_authorization_request_with_wrong_parameters: POP signature not applied");
        if(f_build_pki_secured_request_message_for_authorization(vc_aaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_request(v_inner_at_request))), PX_EC_ALG_FOR_AT, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
          log("*** f_http_build_authorization_request_with_wrong_parameters: ERROR: Failed to generate Authorization Request ***");
          f_selfOrClientSyncAndVerdict("error", e_error);
        }
      }
      log("*** f_http_build_authorization_request_with_wrong_parameters: DEBUG: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data);
      if (p_alter_enc_key == true) {
        /***
            Alter encryption key to prevent decryption
         ***/
        if (ischosen(p_ieee1609dot2_signed_and_encrypted_data.content.encryptedData.recipients[0].certRecipInfo.encKey.eciesNistP256)) {
          p_ieee1609dot2_signed_and_encrypted_data.content.encryptedData.recipients[0].certRecipInfo.encKey.eciesNistP256.c[1] := 'aa'O;
          p_ieee1609dot2_signed_and_encrypted_data.content.encryptedData.recipients[0].certRecipInfo.encKey.eciesNistP256.c[2] := 'bb'O;
        } else {
          p_ieee1609dot2_signed_and_encrypted_data.content.encryptedData.recipients[0].certRecipInfo.encKey.eciesBrainpoolP256r1.c[1] := 'aa'O;
          p_ieee1609dot2_signed_and_encrypted_data.content.encryptedData.recipients[0].certRecipInfo.encKey.eciesBrainpoolP256r1.c[2] := 'bb'O;
        }
        log("*** f_http_build_authorization_request_with_wrong_parameters: DEBUG: Altered enc key= ", p_ieee1609dot2_signed_and_encrypted_data);
      }
      if (p_alter_pks_recipient == true) {
        p_ieee1609dot2_signed_and_encrypted_data.content.encryptedData.recipients[0].pskRecipInfo := int2oct(314259265, 8); // NOT equal to the HashedId8 of the certificate CERT_AA
        log("*** f_http_build_authorization_request_with_wrong_parameters: DEBUG: Altered pskRecipInfo= ", p_ieee1609dot2_signed_and_encrypted_data);
      }
      log("*** f_http_build_authorization_request_with_wrong_parameters: DEBUG: p_request_hash= ", p_request_hash);
    } // End of function f_http_build_authorization_request_with_wrong_parameters

    function f_http_build_authorization_response(
                                                 in template (omit) InnerAtRequest p_inner_at_request := omit,
                                                 in AuthorizationResponseCode p_responseCode := ok,
                                                 in Oct16 p_request_hash,
                                                 in octetstring p_private_key := ''O,
                                                 in octetstring p_digest := ''O,
                                                 in Oct16 p_aes_sym_key,
                                                 out InnerAtResponse p_inner_at_response,
                                                 out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data
                                                 ) return boolean {
      // Local variables
      var bitstring v_msg_bit;
      var octetstring v_msg;
      var Oct12 v_nonce;
      var Ieee1609Dot2Data v_ieee1609dot2_signed_data;
      var EtsiTs103097Certificate v_at_certificate;
      var boolean p_result := false;

      log(">>> f_http_build_authorization_response: p_inner_at_request= ", p_inner_at_request);
      log(">>> f_http_build_authorization_response: p_responseCode= ", p_responseCode);
      log(">>> f_http_build_authorization_response: p_request_hash= ", p_request_hash);
      log(">>> f_http_build_authorization_response: p_private_key= ", p_private_key);
      log(">>> f_http_build_authorization_response: p_digest= ", p_digest);
      log(">>> f_http_build_authorization_response: p_aes_sym_key= ", p_aes_sym_key);
      
      // Check expectred response
      if (p_responseCode != ok) {
        p_inner_at_response := valueof(
                                       m_innerAtResponse_ko(
                                                            p_request_hash,
                                                            p_responseCode
                                                            )
                                       );
        p_result := true;
      } else {
        // Generate the certificate
        if (f_generate_at_certificate_for_inner_at_response(valueof(p_inner_at_request), p_private_key, p_digest, v_at_certificate) == false) {
          log("f_http_build_authorization_response: Failed to generate the certificate");
          p_inner_at_response := valueof(
                                         m_innerAtResponse_ko(
                                                              p_request_hash,
                                                              its_aa_incompleterequest
                                                              )
                                         );
        } else {
          p_inner_at_response := valueof(
                                         m_innerAtResponse_ok(
                                                              p_request_hash,
                                                              v_at_certificate
                                                              )
                                         );
        }
      }

      // Secure the response
      log("f_http_build_authorization_response: p_inner_at_response= ", p_inner_at_response);
      v_msg := bit2oct(encvalue(m_etsiTs102941Data_inner_at_response(p_inner_at_response)));
      v_nonce := substr(f_hashWithSha256(int2oct((f_getCurrentTimeUtc() * 1000), 16)), 0, 12); // Random value
      // TODO Consider  Sha384: m_signerIdentifier_digest(f_hashedId8FromSha384(p_digest))
      if (f_build_pki_secured_response_message(p_private_key,
                                               valueof(m_signerIdentifier_digest(f_hashedId8FromSha256(p_digest))),//  in SignerIdentifier p_signer_identifier,
                                               v_msg,
                                               p_aes_sym_key,
                                               v_nonce,
                                               p_ieee1609dot2_signed_and_encrypted_data
                                               ) == false) {
        log("f_http_build_authorization_response: Failed to generate the certificate");
        p_inner_at_response := valueof(
                                       m_innerAtResponse_ko(
                                                            p_request_hash,
                                                            its_aa_deniedpermissions
                                                            )
                                       );
      } else {
        p_result := true;
      }

      log("<<< f_http_build_authorization_response: p_result= ", p_result);
      log("<<< f_http_build_authorization_response: p_inner_at_response= ", p_inner_at_response);
      return p_result;
    } // End of function f_http_build_authorization_response
    
    function f_http_build_authorization_validation_request(
                                                           in InnerAtRequest p_inner_at_request,
                                                           in octetstring p_public_key_compressed,
                                                           in integer p_compressed_key_mode,
                                                           in octetstring p_private_enc_key,
                                                           in octetstring p_public_compressed_enc_key,
                                                           in integer p_compressed_enc_key_mode,
                                                           out Oct16 p_aes_sym_key,
                                                           out Oct16 p_encrypted_sym_key,
                                                           out Oct16 p_authentication_vector,
                                                           out Oct12 p_nonce,
                                                           out octetstring p_salt,
                                                           out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                           out Oct32 p_request_hash
                                                           ) runs on ItsPkiHttp {
      // Local variables
      var AuthorizationValidationRequest v_authorization_validation_request;
      var bitstring v_authorization_validation_request_msg;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;

      log(">>> f_http_build_authorization_validation_request");

      // Copy the sharedAtRequest component from the InnerAtRequest received in the AuthorizationRequestMessage
      v_authorization_validation_request.sharedAtRequest := p_inner_at_request.sharedAtRequest;
      // Copy the ecSignature component from the InnerAtRequest received in the AuthorizationRequestMessage or AuthorizationRequestMessageWithPop
      v_authorization_validation_request.ecSignature := p_inner_at_request.ecSignature;
      // Secure the InnerAtRequest message
      if (f_extract_enc_key(vc_eaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("f_http_build_authorization_validation_request: Non canonical EA certificate");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_authorization_validation_request: Public encryption key: ", v_public_enc_key);
      log("f_http_build_authorization_validation_request: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_eaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      log("f_http_build_authorization_validation_request: vc_aaHashedId8: ", vc_aaHashedId8);
      log("f_http_build_authorization_validation_request: p_salt: ", p_salt);
      if(f_build_pki_secured_request_message_signed_with_pop(vc_aaPrivateKey, valueof(m_signerIdentifier_digest(vc_aaHashedId8)), vc_eaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_validation_request(v_authorization_validation_request))), PX_EC_ALG_FOR_ATV, -, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
        log("f_http_build_authorization_validation_request: Failed to generate Authorization Request");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_authorization_validation_request: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data);
      log("f_http_build_authorization_validation_request: p_request_hash= ", p_request_hash);
    } // End of function f_http_build_authorization_validation_request

    function f_http_build_invalid_authorization_validation_request(
                                                                   in InnerAtRequest p_inner_at_request,
                                                                   in octetstring p_public_key_compressed,
                                                                   in integer p_compressed_key_mode,
                                                                   in octetstring p_private_enc_key,
                                                                   in octetstring p_public_compressed_enc_key,
                                                                   in integer p_compressed_enc_key_mode,
                                                                   out Oct16 p_aes_sym_key,
                                                                   out Oct16 p_encrypted_sym_key,
                                                                   out Oct16 p_authentication_vector,
                                                                   out Oct12 p_nonce,
                                                                   out octetstring p_salt,
                                                                   out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                                   out Oct32 p_request_hash
                                                                   ) runs on ItsPkiHttp {
      // Local variables
      var AuthorizationValidationRequest v_authorization_validation_request;
      var bitstring v_authorization_validation_request_msg;
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;

      log(">>> f_http_build_invalid_authorization_validation_request");

      // Copy the sharedAtRequest component from the InnerAtRequest received in the AuthorizationRequestMessage
      v_authorization_validation_request.sharedAtRequest := p_inner_at_request.sharedAtRequest;
      // Copy the ecSignature component from the InnerAtRequest received in the AuthorizationRequestMessage or AuthorizationRequestMessageWithPop
      v_authorization_validation_request.ecSignature := p_inner_at_request.ecSignature;
      // Secure the InnerAtRequest message
      if (f_extract_enc_key(vc_eaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) {
        log("f_http_build_invalid_authorization_validation_request: Non canonical EA certificate");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_invalid_authorization_validation_request: Public encryption key: ", v_public_enc_key);
      log("f_http_build_invalid_authorization_validation_request: Public encryption key comp: ", v_compressed_enc_key_mode);
      p_salt := vc_eaWholeHash256; // IEEE 1609.2: If the encryption key was obtained from a certificate c, P1 is SHA-256 (c), where c is the COER encoding of the certificate, canonicalized per 6.4.3.
      log("f_http_build_invalid_authorization_validation_request: vc_aaHashedId8: ", vc_aaHashedId8);
      log("f_http_build_invalid_authorization_validation_request: p_salt: ", p_salt);
      if(f_build_pki_secured_request_message_signed_with_pop(vc_aaPrivateKey, valueof(m_signerIdentifier_digest(vc_aaHashedId8)), vc_eaHashedId8/*recipientId*/, v_public_enc_key, v_compressed_enc_key_mode, p_salt, bit2oct(encvalue(m_etsiTs102941Data_authorization_validation_request(v_authorization_validation_request))), PX_EC_ALG_FOR_ATV, true, p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash) == false) {
        log("f_http_build_invalid_authorization_validation_request: Failed to generate Authorization Request");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      log("f_http_build_invalid_authorization_validation_request: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data);
      log("f_http_build_invalid_authorization_validation_request: p_request_hash= ", p_request_hash);
    } // End of function f_http_build_invalid_authorization_validation_request

    function f_http_build_authorization_validation_response(
                                                            in SharedAtRequest p_shared_at_request,
                                                            in AuthorizationValidationResponseCode p_responseCode := ok,
                                                            in Oct16 p_request_hash,
                                                            in octetstring p_private_key := ''O,
                                                            in octetstring p_digest := ''O,
                                                            in Oct16 p_aes_sym_key,
                                                            out AuthorizationValidationResponse p_authorization_validation_response,
                                                            out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data
                                                            ) return boolean {
      // Local variables
      var bitstring v_msg_bit;
      var octetstring v_msg;
      var Oct12 v_nonce;
      var Ieee1609Dot2Data v_ieee1609dot2_signed_data;
      var EtsiTs103097Certificate v_at_certificate;
      var boolean p_result := false;

      log(">>> f_http_build_authorization_validation_response: p_shared_at_request= ", p_shared_at_request);
      log(">>> f_http_build_authorization_validation_response: p_responseCode= ", p_responseCode);
      log(">>> f_http_build_authorization_validation_response: p_request_hash= ", p_request_hash);
      log(">>> f_http_build_authorization_validation_response: p_private_key= ", p_private_key);
      log(">>> f_http_build_authorization_validation_response: p_digest= ", p_digest);
      log(">>> f_http_build_authorization_validation_response: p_aes_sym_key= ", p_aes_sym_key);
      
      // Check expectred response
      if (p_responseCode != ok) {
        p_authorization_validation_response := valueof(
                                                       m_authorizationValidationResponse_ko(
                                                                                            p_request_hash,
                                                                                            p_responseCode
                                                                                            )
                                                       );
        p_result := true;
      } else {
        p_authorization_validation_response := valueof(m_authorizationValidationResponse_ok(
                                                                                            p_request_hash,
                                                                                            p_shared_at_request.requestedSubjectAttributes
                                                                                            )
                                                        );
      }
      log("f_http_build_authorization_validation_response: p_authorization_validation_response= ", p_authorization_validation_response);
      // Encapsulte authorization validation response into EtsiTs102941Data
      v_msg := bit2oct(encvalue(m_etsiTs102941Data_authorization_validation_response(p_authorization_validation_response)));
      // Secure the response
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      v_nonce := substr(f_hashWithSha256(int2oct((f_getCurrentTimeUtc() * 1000), 16)), 0, 12); // Random value
      if (f_build_pki_secured_response_message(p_private_key,
                                               valueof(m_signerIdentifier_digest(f_hashedId8FromSha256(p_digest))),//  in SignerIdentifier p_signer_identifier,
                                               v_msg,
                                               p_aes_sym_key,
                                               v_nonce,
                                               p_ieee1609dot2_signed_and_encrypted_data
                                               ) == false) {
        log("f_http_build_authorization_validation_response: Failed to generate the certificate");
        p_authorization_validation_response := valueof(
                                                       m_authorizationValidationResponse_ko(
                                                                                            p_request_hash,
                                                                                            deniedpermissions
                                                                                            )
                                                       );
      } else {
        p_result := true;
      }
      
      log("<<< f_http_build_authorization_validation_response: p_result= ", p_result);
      log("<<< f_http_build_authorization_validation_response: p_authorization_validation_response= ", p_authorization_validation_response);
      return p_result;
    } // End of function f_http_build_authorization_validation_response
    
    function f_http_build_dc_request( // TODO Cleanup parameters
                                     in charstring p_ea_certificate_id,
                                     in charstring p_aa_certificate_id,
                                     in charstring p_rca_certificate_id,
                                     out octetstring p_private_key,
                                     out octetstring p_public_key_compressed,
                                     out integer p_compressed_mode,
                                     out Oct16 p_aes_sym_key,
                                     out Oct16 p_encrypted_sym_key,
                                     out Oct16 p_authentication_vector,
                                     out Oct12 p_nonce,
                                     out octetstring p_salt,
                                     out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                     out Oct32 p_request_hash
                                     ) runs on ItsPkiHttp {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    } // End of function 
  } // End of group http

  group generate_certificates {

    function f_generate_ec_certificate(
                                       out octetstring p_private_key,
                                       out Certificate p_ec_certificate
                                       ) return boolean {
      var octetstring v_public_key_x;
      var octetstring v_public_key_y;
      var octetstring p_public_key_compressed;
      var integer p_compressed_mode;
      var EccP256CurvePoint v_ecc_p256_curve_point;
      var SequenceOfPsidSsp v_appPermissions := { // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs
        valueof(m_appPermissions(36, { bitmapSsp := PX_INNER_EC_CERTFICATE_BITMAP_SSP_CAM })),
        valueof(m_appPermissions(37, { bitmapSsp := PX_INNER_EC_CERTFICATE_BITMAP_SSP_DENM }))
      };
      var template (value) EtsiTs103097Certificate v_cert;
      var bitstring v_tbs;
      var Oct32 v_sig;
      var bitstring v_enc_msg;
      var PublicVerificationKey v_public_verification_key;
      
      log(">>> f_generate_ec_certificate");
      log("f_generate_ec_certificate: PX_EC_ALG_FOR_EC=", PX_EC_ALG_FOR_EC);
      log("f_generate_ec_certificate: PX_VE_ALG=", PX_VE_ALG);
      
      // Generate verification keys for the certificate
      if (f_generate_key_pair(p_private_key, v_public_key_x, v_public_key_y, p_public_key_compressed, p_compressed_mode) == false) {
        log("f_generate_ec_certificate: Failed to generate verification key");
        return false;
      }
      if (p_compressed_mode == 0) {
        v_ecc_p256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(p_public_key_compressed));
      } else {
        v_ecc_p256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(p_public_key_compressed));
      }

      if (PX_EC_ALG_FOR_EC == e_nist_p256) {
        v_public_verification_key := valueof(
                                             m_publicVerificationKey_ecdsaNistP256(
                                                                                   v_ecc_p256_curve_point
                                                                                   ));
      } else if (PX_EC_ALG_FOR_EC == e_brainpool_p256_r1) {
        v_public_verification_key := valueof(
                                             m_publicVerificationKey_ecdsaBrainpoolP256r1(
                                                                                          v_ecc_p256_curve_point
                                                                                          ));
      } else {
        log("f_generate_ec_certificate: Wrong encryption algorithm, check PX_EC_ALG_FOR_xx");
        return false;
      }
      v_cert := m_etsiTs103097Certificate(
                                          m_issuerIdentifier_sha256AndDigest(f_hashedId8FromSha256(f_hashWithSha256('616263'O))),
                                          m_toBeSignedCertificate_at(
                                                                     v_appPermissions,
                                                                     m_verificationKeyIndicator_verificationKey(
                                                                                                                v_public_verification_key
                                                                                                                ),
                                                                     m_validityPeriod(
                                                                                      f_getCurrentTime() / 1000,
                                                                                      m_duration_in_hours(PX_GENERATED_CERTIFICATE_DURATION)
                                                                                      ),
                                                                     m_geographicRegion_identifiedRegion(
                                                                                                         {
                                                                                                           m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_2),
                                                                                                           m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_2)
                                                                                                           }
                                                                                                         ),
                                                                     PX_GENERATED_CERTIFICATE_SUBJECT_ASSURENCE_LEVEL
                                                                     )
                                          );
      // Encode it ==> Get octetstring
      v_tbs := encvalue(v_cert.toBeSigned);
      // Sign the certificate
      v_sig := f_signWithEcdsa(bit2oct(v_tbs), int2oct(11, 32), p_private_key);
      if ((PX_VE_ALG == e_nist_p256) or (PX_VE_ALG == e_brainpool_p256_r1)) {
        v_cert.signature_ := m_signature_ecdsaNistP256(
                                                       m_ecdsaP256Signature(
                                                                            m_eccP256CurvePoint_x_only(
                                                                                                       substr(v_sig, 0, 32)
                                                                                                       ),
                                                                            substr(v_sig, 32, 32)
                                                                            )
                                                       );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        v_cert.signature_ := m_signature_ecdsaBrainpoolP384r1(
                                                              m_ecdsaP384Signature(
                                                                                   m_eccP384CurvePoint_x_only(
                                                                                                              substr(v_sig, 0, 48)
                                                                                                              ),
                                                                                   substr(v_sig, 48, 48)
                                                                                   )
                                                              );
      }
      log("f_generate_ec_certificate: v_cert= ", v_cert);
      
      p_ec_certificate := valueof(v_cert);
      return true;
    } // End of function f_generate_ec_certificate
    
    function f_generate_ec_certificate_for_inner_ec_response(
                                                             in InnerEcRequest p_inner_ec_request,
                                                             in octetstring p_private_key,
                                                             in octetstring p_digest,
                                                             out EtsiTs103097Certificate p_ec_certificate,
                                                             out HashedId8 p_ec_certificate_hashed_id8
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                             ) return boolean {
      var CertificateId v_certificate_id;
      var EtsiTs103097Certificate v_cert;
      var IssuerIdentifier v_issuer;
      var bitstring v_tbs;
      var octetstring v_sig;
      
      log(">>> f_generate_ec_certificate_for_inner_ec_response: p_inner_ec_request: ", p_inner_ec_request);
      log(">>> f_generate_ec_certificate_for_inner_ec_response: p_digest: ", p_digest);

      v_issuer := valueof(m_issuerIdentifier_sha256AndDigest(f_hashedId8FromSha256(p_digest))); // TODO Check sha256/384 f_hashedId8FromSha384
      if (not(ispresent(p_inner_ec_request.requestedSubjectAttributes.id))) {
        v_certificate_id := { none_ := NULL };
      } else {
        v_certificate_id := p_inner_ec_request.requestedSubjectAttributes.id;
      }
      v_cert := valueof(
                        m_etsiTs103097Certificate(
                                                  v_issuer,
                                                  m_toBeSignedCertificate_ec(
                                                                             v_certificate_id,
                                                                             p_inner_ec_request.requestedSubjectAttributes.appPermissions,
                                                                             m_verificationKeyIndicator_verificationKey(
                                                                                                                        p_inner_ec_request.publicKeys.verificationKey
                                                                                                                        ),
                                                                             p_inner_ec_request.requestedSubjectAttributes.validityPeriod,
                                                                             p_inner_ec_request.requestedSubjectAttributes.region,
                                                                             p_inner_ec_request.requestedSubjectAttributes.assuranceLevel,
                                                                             p_inner_ec_request.publicKeys.encryptionKey
                                                                             )
                                                  )
                        );
      // Encode it ==> Get octetstring
      v_tbs := encvalue(v_cert.toBeSigned);
      // Sign the certificate
      v_sig := f_signWithEcdsa(bit2oct(v_tbs), p_digest, p_private_key);
      if (PX_VE_ALG == e_nist_p256) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaNistP256(
                                                               m_ecdsaP256Signature(
                                                                                    m_eccP256CurvePoint_x_only(
                                                                                                               substr(v_sig, 0, 32)
                                                                                                               ),
                                                                                    substr(v_sig, 32, 32)
                                                                                    )
                                                               )
                                     );
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaBrainpoolP256r1(
                                                                      m_ecdsaP256Signature(
                                                                                           m_eccP256CurvePoint_x_only(
                                                                                                                      substr(v_sig, 0, 32)
                                                                                                                      ),
                                                                                           substr(v_sig, 32, 32)
                                                                                           )
                                                                      )
                                     );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaBrainpoolP384r1(
                                                                      m_ecdsaP384Signature(
                                                                                           m_eccP384CurvePoint_x_only(
                                                                                                                      substr(v_sig, 0, 48)
                                                                                                                      ),
                                                                                           substr(v_sig, 48, 48)
                                                                                           )
                                                                      )
                                     );
      }
      p_ec_certificate := valueof(v_cert);

      // Encode it and calculate HashedId8
      v_tbs := encvalue(p_ec_certificate);
      p_ec_certificate_hashed_id8 := f_hashedId8FromSha256(f_hashWithSha256(bit2oct(v_tbs)));
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      log("f_generate_ec_certificate_for_inner_ec_response: p_ec_certificate= ", p_ec_certificate);
      log("f_generate_ec_certificate_for_inner_ec_response: p_ec_certificate_hashed_id8= ", p_ec_certificate_hashed_id8);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      
      return true;
    } // End of function f_generate_ec_certificate_for_inner_ec_response
    
    function f_generate_at_certificate_for_inner_at_response(
                                                             in InnerAtRequest p_inner_at_request,
                                                             in octetstring p_private_key,
                                                             in octetstring p_digest,
                                                             out EtsiTs103097Certificate p_at_certificate
                                                             ) return boolean {
      var EtsiTs103097Certificate v_cert;
      var IssuerIdentifier v_issuer;
      var bitstring v_tbs;
      var octetstring v_sig;
      
      v_issuer := valueof(m_issuerIdentifier_sha256AndDigest(f_hashedId8FromSha256(p_digest))); // TODO Check sha256/384 f_hashedId8FromSha384
      v_cert := valueof(
                        m_etsiTs103097Certificate(
                                                  v_issuer,
                                                  m_toBeSignedCertificate_at(
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.appPermissions,
                                                                             m_verificationKeyIndicator_verificationKey(
                                                                                                                        p_inner_at_request.publicKeys.verificationKey
                                                                                                                        ),
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.validityPeriod,
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.region,
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.assuranceLevel,
                                                                             p_inner_at_request.publicKeys.encryptionKey
                                                                             )
                                                  )
                        );
      // Encode it ==> Get octetstring
      v_tbs := encvalue(v_cert.toBeSigned);
      // Sign the certificate
      v_sig := f_signWithEcdsa(bit2oct(v_tbs), p_digest, p_private_key);
      log("f_generate_at_certificate_for_inner_at_response: PX_VE_ALG=", PX_VE_ALG);
      if (PX_VE_ALG == e_nist_p256) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaNistP256(
                                                               m_ecdsaP256Signature(
                                                                                    m_eccP256CurvePoint_x_only(
                                                                                                               substr(v_sig, 0, 32)
                                                                                                               ),
                                                                                    substr(v_sig, 32, 32)
                                                                                    )
                                                               )
                                     );
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaBrainpoolP256r1(
                                                                      m_ecdsaP256Signature(
                                                                                           m_eccP256CurvePoint_x_only(
                                                                                                                      substr(v_sig, 0, 32)
                                                                                                                      ),
                                                                                           substr(v_sig, 32, 32)
                                                                                           )
                                                                      )
                                     );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaBrainpoolP384r1(
                                                                      m_ecdsaP384Signature(
                                                                                           m_eccP384CurvePoint_x_only(
                                                                                                                      substr(v_sig, 0, 48)
                                                                                                                      ),
                                                                                           substr(v_sig, 48, 48)
                                                                                           )
                                                                      )
                                     );
      }
      p_at_certificate := valueof(v_cert);
      log("f_generate_at_certificate_for_inner_at_response: p_at_certificate= ", p_at_certificate);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      
      return true;
    } // End of function f_generate_at_certificate_for_inner_at_response
    
    function f_generate_at_certificate_for_authorization_response(
                                                                  in InnerAtRequest p_inner_at_request,
                                                                  in octetstring p_private_key,
                                                                  in octetstring p_digest,
                                                                  out EtsiTs103097Certificate p_at_certificate
                                                                  ) return boolean {
      var EtsiTs103097Certificate v_cert;
      var IssuerIdentifier v_issuer;
      var bitstring v_tbs;
      var octetstring v_sig;
      
      log(">>> f_generate_at_certificate_for_authorization_response");

      v_issuer := valueof(m_issuerIdentifier_sha256AndDigest(f_hashedId8FromSha256(p_digest))); // TODO Check sha256/384 f_hashedId8FromSha384
      v_cert := valueof(
                        m_etsiTs103097Certificate(
                                                  v_issuer,
                                                  m_toBeSignedCertificate_ec(
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.id,
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.appPermissions,
                                                                             m_verificationKeyIndicator_verificationKey(
                                                                                                                        p_inner_at_request.publicKeys.verificationKey
                                                                                                                        ),
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.validityPeriod,
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.region,
                                                                             p_inner_at_request.sharedAtRequest.requestedSubjectAttributes.assuranceLevel,
                                                                             p_inner_at_request.publicKeys.encryptionKey
                                                                             )
                                                  )
                        );
      // Encode it ==> Get octetstring
      v_tbs := encvalue(v_cert.toBeSigned);
      // Sign the certificate
      v_sig := f_signWithEcdsa(bit2oct(v_tbs), p_digest, p_private_key);
      if (PX_VE_ALG == e_nist_p256) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaNistP256(
                                                               m_ecdsaP256Signature(
                                                                                    m_eccP256CurvePoint_x_only(
                                                                                                               substr(v_sig, 0, 32)
                                                                                                               ),
                                                                                    substr(v_sig, 32, 32)
                                                                                    )
                                                               )
                                     );
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaBrainpoolP256r1(
                                                                      m_ecdsaP256Signature(
                                                                                           m_eccP256CurvePoint_x_only(
                                                                                                                      substr(v_sig, 0, 32)
                                                                                                                      ),
                                                                                           substr(v_sig, 32, 32)
                                                                                           )
                                                                      )
                                     );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        v_cert.signature_ := valueof(
                                     m_signature_ecdsaBrainpoolP384r1(
                                                                      m_ecdsaP384Signature(
                                                                                           m_eccP384CurvePoint_x_only(
                                                                                                                      substr(v_sig, 0, 48)
                                                                                                                      ),
                                                                                           substr(v_sig, 48, 48)
                                                                                           )
                                                                      )
                                     );
      }
      p_at_certificate := valueof(v_cert);
      log("f_generate_at_certificate_for_authorization_response: p_at_certificate= ", p_at_certificate);
      
      return true;
    } // End of function f_generate_at_certificate_for_authorization_response
    
  } // End of group generate_certificates 
  
  group inner_ec_xxx {
    
    function f_generate_inner_ec_request(
                                         out octetstring p_private_key,
                                         out octetstring p_public_key_compressed,
                                         out integer p_compressed_mode,
                                         out InnerEcRequest p_inner_ec_request
                                         ) runs on ItsPkiHttp return boolean {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      // Local variables
      var Oct32 v_public_key_x;
      var Oct32 v_public_key_y;
      var PublicVerificationKey v_public_verification_key;

      log (">>> f_generate_inner_ec_request");
      log("f_generate_inner_ec_request: PX_VE_ALG=", PX_VE_ALG);
      
      // Generate keys for the certificate to be requested
      if (f_generate_key_pair(p_private_key, v_public_key_x, v_public_key_y, p_public_key_compressed, p_compressed_mode) == false) {
        log ("f_generate_inner_ec_request: failed to generate keys");
        return false;
      }
      // Build the Proof of Possession InnerEcRequest
      if (PX_VE_ALG == e_nist_p256) {
        var EccP256CurvePoint v_eccP256_curve_point;
        if (p_compressed_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(p_public_key_compressed));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(p_public_key_compressed));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaNistP256(v_eccP256_curve_point));
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        var EccP256CurvePoint v_eccP256_curve_point;
        if (p_compressed_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(p_public_key_compressed));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(p_public_key_compressed));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP256r1(v_eccP256_curve_point));
      } else {
        var EccP384CurvePoint v_eccP384_curve_point;
        if (p_compressed_mode == 0) {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_0(p_public_key_compressed));
        } else {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_1(p_public_key_compressed));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP384r1(v_eccP384_curve_point));
      }
      if (PICS_EC_SUBJECT_ATTRIBUT_ID) {
        p_inner_ec_request := valueof(
                                      m_innerEcRequest(
                                                       PICS_ITS_S_CANONICAL_ID,
                                                       m_publicKeys(
                                                                    v_public_verification_key
                                                                    ),
                                                       m_certificateSubjectAttributes_id_name(
                                                                                              oct2char(PICS_ITS_S_CANONICAL_ID) & int2str(f_getCurrentTime()), // ETSI TS  103 097 Clause 7.2.2 Enrolment credential 
                                                                                              { // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs
                                                                                                valueof(m_appPermissions(c_its_aid_SCR, { bitmapSsp := PX_INNER_EC_CERTFICATE_BITMAP_SSP_SCR }))
                                                                                                },
                                                                                              m_validityPeriod(
                                                                                                               f_getCurrentTime() / 1000,
                                                                                                               m_duration_in_hours(PX_GENERATED_CERTIFICATE_DURATION)
                                                                                                               ),
                                                                                              m_geographicRegion_identifiedRegion(
                                                                                                                                  {
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_1),
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_2)
                                                                                                                                    }
                                                                                                                                  ),
                                                                                              PX_GENERATED_CERTIFICATE_SUBJECT_ASSURENCE_LEVEL
                                                                                              )
                                                       )
                                      );
      } else {
        p_inner_ec_request := valueof(
                                      m_innerEcRequest(
                                                       PICS_ITS_S_CANONICAL_ID,
                                                       m_publicKeys(
                                                                    v_public_verification_key
                                                                    ),
                                                       m_certificateSubjectAttributes_id_omit( // ETSI TS  103 097 Clause 7.2.2 Enrolment credential 
                                                                                              { // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs
                                                                                                valueof(m_appPermissions(c_its_aid_SCR, { bitmapSsp := PX_INNER_EC_CERTFICATE_BITMAP_SSP_SCR }))
                                                                                                },
                                                                                              m_validityPeriod(
                                                                                                               f_getCurrentTime() / 1000,
                                                                                                               m_duration_in_hours(PX_GENERATED_CERTIFICATE_DURATION)
                                                                                                               ),
                                                                                              m_geographicRegion_identifiedRegion(
                                                                                                                                  {
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_1),
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_2)
                                                                                                                                    }
                                                                                                                                  ),
                                                                                              PX_GENERATED_CERTIFICATE_SUBJECT_ASSURENCE_LEVEL
                                                                                              )
                                                       )
                                      );
      }
      // Remove geographical region (ETAS)
      if (not(PICS_EC_SUBJECT_ATTRIBUT_REGION)) {
        p_inner_ec_request.requestedSubjectAttributes.region := omit;
      }
      log("f_generate_inner_ec_request: PICS_SECPKI_REENROLMENT: ", PICS_SECPKI_REENROLMENT);
      log("f_generate_inner_ec_request: vc_ec_keys_counter: ", vc_ec_keys_counter);
      if (PICS_SECPKI_REENROLMENT and (vc_ec_keys_counter > 0)) { // This is a re-enrolment, the identifier of its current valid Enrolment Credential
        log("f_generate_inner_ec_request: This is a re-enrolment: vc_ec_keys_counter= ", vc_ec_keys_counter);
        log("f_generate_inner_ec_request: This is a re-enrolment: vc_ec_hashed_id8[vc_ec_keys_counter - 1]= ", vc_ec_hashed_id8[vc_ec_keys_counter - 1]);
        p_inner_ec_request.itsId := vc_ec_hashed_id8[vc_ec_keys_counter - 1];
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      }
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      log("<<< f_generate_inner_ec_request: ", p_inner_ec_request);
      
      return true;
    } // End of function f_generate_inner_ec_request
    
    function f_generate_inner_ec_request_with_wrong_parameters(
                                                               in SequenceOfPsidSsp p_appPermissions,
                                                               in octetstring p_canonical_id := PICS_ITS_S_CANONICAL_ID,
                                                               in Time32 p_start,
                                                               in Duration p_duration,
                                                               in boolean p_alter_private_key := false,
                                                               out octetstring p_private_key,
                                                               out octetstring p_public_key_compressed,
                                                               out integer p_compressed_mode,
                                                               out InnerEcRequest p_inner_ec_request
                                                               ) runs on ItsPkiHttp return boolean {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      // Local variables
      var Oct32 v_public_key_x;
      var Oct32 v_public_key_y;
      var octetstring v_private_key;
      var octetstring v_public_key_compressed;
      var integer v_compressed_mode;
      var PublicVerificationKey v_public_verification_key;

      log (">>> f_generate_inner_ec_request_with_wrong_parameters");
      // Generate keys for the certificate to be requested
      if (f_generate_key_pair(p_private_key, v_public_key_x, v_public_key_y, p_public_key_compressed, p_compressed_mode) == false) {
        log ("f_generate_inner_ec_request_with_wrong_parameters: failed to generate keys");
        return false;
      }
      if (p_alter_private_key == false) {
        v_private_key := p_private_key;
        v_public_key_compressed := p_public_key_compressed;
        v_compressed_mode := p_compressed_mode;
      } else {
        log ("f_generate_inner_ec_request_with_wrong_parameters: Alter verify private key");
        if (f_generate_key_pair(v_private_key, v_public_key_x, v_public_key_y, v_public_key_compressed, v_compressed_mode) == false) {
          log ("f_generate_inner_ec_request_with_wrong_parameters: failed to generate keys");
          return false;
        }
      }
      // Build the Proof of Possession InnerEcRequest
      log("f_generate_inner_ec_request_with_wrong_parameters: PX_VE_ALG=", PX_VE_ALG);
      if (PX_VE_ALG == e_nist_p256) {
        var EccP256CurvePoint v_eccP256_curve_point;
        if (v_compressed_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_key_compressed));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_key_compressed));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaNistP256(v_eccP256_curve_point));
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        var EccP256CurvePoint v_eccP256_curve_point;
        if (v_compressed_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_key_compressed));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_key_compressed));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP256r1(v_eccP256_curve_point));
      } else {
        var EccP384CurvePoint v_eccP384_curve_point;
        if (v_compressed_mode == 0) {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_0(v_public_key_compressed));
        } else {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_1(v_public_key_compressed));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP384r1(v_eccP384_curve_point));
      }
      if (PICS_EC_SUBJECT_ATTRIBUT_ID) {
        p_inner_ec_request := valueof(
                                      m_innerEcRequest(
                                                      p_canonical_id,
                                                      m_publicKeys(
                                                                    v_public_verification_key
                                                                    ),
                                                      m_certificateSubjectAttributes_id_name(
                                                                                              oct2char(PICS_ITS_S_CANONICAL_ID),
                                                                                              p_appPermissions, // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs
                                                                                              m_validityPeriod(
                                                                                                              p_start,
                                                                                                              p_duration
                                                                                                              ),
                                                                                              m_geographicRegion_identifiedRegion(
                                                                                                                                  {
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_1),
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_2)
                                                                                                                                    }
                                                                                                                                  ),
                                                                                              PX_GENERATED_CERTIFICATE_SUBJECT_ASSURENCE_LEVEL
                                                                                              )
                                                      )
                                      );
      } else {
        p_inner_ec_request := valueof(
                                      m_innerEcRequest(
                                                      p_canonical_id,
                                                      m_publicKeys(
                                                                    v_public_verification_key
                                                                    ),
                                                      m_certificateSubjectAttributes_id_omit( // ETSI TS  103 097 Clause 7.2.2 Enrolment credential 
                                                                                              p_appPermissions, // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs
                                                                                              m_validityPeriod(
                                                                                                              p_start,
                                                                                                              p_duration
                                                                                                              ),
                                                                                              m_geographicRegion_identifiedRegion(
                                                                                                                                  {
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_1),
                                                                                                                                    m_identifiedRegion_country_only(PX_GENERATED_CERTIFICATE_REGION_COUNTRY_2)
                                                                                                                                    }
                                                                                                                                  ),
                                                                                              PX_GENERATED_CERTIFICATE_SUBJECT_ASSURENCE_LEVEL
                                                                                              )
                                                      )
                                      );
      }// Remove geographical region (ETAS)
      if (not(PICS_EC_SUBJECT_ATTRIBUT_REGION)) {
        p_inner_ec_request.requestedSubjectAttributes.region := omit;
      }
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      log("f_generate_inner_ec_request_with_wrong_parameters: ", p_inner_ec_request);
      
      return true;
    } // End of function f_generate_inner_ec_request_with_wrong_parameters
    
    function f_generate_inner_ec_request_signed_for_pop(
                                                        in octetstring p_private_key,
                                                        in InnerEcRequest p_inner_ec_request,
                                                        out Ieee1609Dot2Data p_inner_ec_request_signed_for_pop
    ) runs on ItsPkiHttp return boolean {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      // Local variables
      var template (value) EccP256CurvePoint v_eccP256_curve_point;
      var octetstring v_encoded_inner_ec_request;
      var template (value) ToBeSignedData v_tbs;
      var octetstring v_tbs_signed;
      var Signature v_signature;
      
      // Encode it
      log("f_generate_inner_ec_request_signed_for_pop: encode ", p_inner_ec_request);
      v_encoded_inner_ec_request := bit2oct(encvalue(p_inner_ec_request));
      // Signed the encoded InnerEcRequestSignedForPop
      v_tbs := m_toBeSignedData(
                                m_signedDataPayload(
                                                    m_etsiTs103097Data_unsecured(
                                                                                 v_encoded_inner_ec_request
                                                                                 )
                                                   ),
                                m_headerInfo_inner_pki_request(
                                                               -,
                                                               (f_getCurrentTime() * 1000) //us
                                                               )
                               );
      // Signed the encoded InnerEcRequestSignedForPop
      log("f_generate_inner_ec_request_signed_for_pop: tbs= ", v_tbs);
      log("f_generate_inner_ec_request_signed_for_pop: tbs= ", bit2oct(encvalue(v_tbs)));
      v_tbs_signed := f_signWithEcdsa(bit2oct(encvalue(v_tbs)), int2oct(0, 32), p_private_key);
      // Finalyse signed InnerEcRequestSignedForPop
      if (PX_VE_ALG == e_nist_p256) {
        v_signature := valueof(
                               m_signature_ecdsaNistP256(
                                                         m_ecdsaP256Signature(
                                                                              m_eccP256CurvePoint_x_only(
                                                                                                         substr(v_tbs_signed, 0, 32)
                                                                                                         ),
                                                                              substr(v_tbs_signed, 32, 32)
                                                                              )
                                                         )
                               );
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
        v_signature := valueof(
                               m_signature_ecdsaBrainpoolP256r1(
                                                                m_ecdsaP256Signature(
                                                                                     m_eccP256CurvePoint_x_only(
                                                                                                                substr(v_tbs_signed, 0, 32)
                                                                                                                ),
                                                                                     substr(v_tbs_signed, 32, 32)
                                                                                     )
                                                                )
                               );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        v_signature := valueof(
                               m_signature_ecdsaBrainpoolP384r1(
                                                                m_ecdsaP384Signature(
                                                                                     m_eccP384CurvePoint_x_only(
                                                                                                                substr(v_tbs_signed, 0, 48)
                                                                                                                ),
                                                                                     substr(v_tbs_signed, 48, 48)
                                                                                     )
                                                                )
                               );
      }
      log("f_generate_inner_ec_request_signed_for_pop: v_signature= ", v_signature);
      p_inner_ec_request_signed_for_pop := valueof(
                                                   m_etsiTs103097Data_signed(
                                                                             m_signedData(
                                                                                          sha256,
                                                                                          v_tbs,
                                                                                          m_signerIdentifier_self,
                                                                                          v_signature
                                                                                          )
                                                                             )
                                                   );
      
      log("<<< f_generate_inner_ec_request_signed_for_pop: p_inner_ec_request_signed_for_pop= ", p_inner_ec_request_signed_for_pop);
      return true;
    } // End of function f_generate_inner_ec_request_signed_for_pop

    function f_verify_inner_ec_request_signed_for_pop(
                                                      in EtsiTs102941Data p_etsi_ts_102941_data,
                                                      out InnerEcRequest p_inner_ec_request
                                                      ) return boolean {
      var bitstring v_msg_bit;

      log(">>> f_verify_inner_ec_request_signed_for_pop: ", p_etsi_ts_102941_data);
      
      // 1. Decode content
      v_msg_bit := oct2bit(p_etsi_ts_102941_data.content.enrolmentRequest.content.signedData.tbsData.payload.data.content.unsecuredData);
      if (decvalue(v_msg_bit, p_inner_ec_request) != 0) {
        log("f_verify_inner_ec_request_signed_for_pop: Failed to decode InnerEcRequest");
        return false;
      } else {
        log("f_verify_inner_ec_request_signed_for_pop: v_inner_ec_request= ", p_inner_ec_request);

        // 2. Verify the InnerEcRequestSignedForPop signature
        // TODO
      }
      
      return true;
    } // End of function f_verify_inner_ec_request_signed_for_pop
    
    function f_generate_inner_ec_response(
                                          in octetstring p_inner_ec_request_hash,
                                          in EtsiTs103097Certificate p_certificate,
                                          out InnerEcResponse p_inner_ec_response
                                         ) return boolean {
      // Local variables
      
      // Build the Proof of Possession InnerEcResponse
      p_inner_ec_response := valueof(
                                     m_innerEcResponse_ok(
                                                          substr(p_inner_ec_request_hash, 0, 16),
                                                          p_certificate
                                                          )
                                     );
      
      return true;
    } // End of function f_generate_inner_ec_response
    
  } // End of group inner_ec_xxx

  group inner_at_xxx {

    function f_generate_inner_at_request(
                                         in Certificate p_aa_certificate,
                                         in SignAlgorithm p_enc_algo := PX_EC_ALG_FOR_EC_SIGN,
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                         in Oct8 p_aa_hashed_id8,
                                         in Certificate p_ea_certificate,
                                         in octetstring p_salt,
                                         in Oct8 p_ea_hashed_id8,
                                         in Certificate p_ec_certificate,
                                         in octetstring p_ec_private_key,
                                         out octetstring p_private_key,
                                         out octetstring p_public_key_compressed,
                                         out integer p_compressed_key_mode,
                                         out octetstring p_private_enc_key,
                                         out octetstring p_public_compressed_enc_key,
                                         out integer p_compressed_enc_key_mode,
                                         out InnerAtRequest p_inner_at_request
                                         ) return boolean {
      // Local variables
      var octetstring v_public_key_x;
      var octetstring v_public_key_y;
      var octetstring v_public_enc_key_x;
      var octetstring v_public_enc_key_y;
      var bitstring v_enc_value;
      var octetstring v_ec_hash;
      var PublicVerificationKey v_public_verification_key;
      var BasePublicEncryptionKey v_public_encryption_key;
      var Oct8 v_ec_hashed_id8;
      var octetstring public_enc_key_x;
      var octetstring public_enc_key_y;
      var Oct32 v_hmac_key;
      var PublicVerificationKey v_verification_tag;
      var PublicEncryptionKey v_encryption_tag;
      var octetstring v_encoded_tag;
      var Oct16 v_key_tag;
      var octetstring v_hash_shared_at_request;
      var template (value) ToBeSignedData v_tbs;
      var octetstring v_tbs_signed;
      var Ieee1609Dot2Data v_signed_at_signature;
      var template (value) EccP256CurvePoint v_eccP256_curve_point;
      var HashAlgorithm v_hashId;
      var Signature v_signature;
      var SequenceOfPsidSsp v_appPermissions := { // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs
        valueof(m_appPermissions(c_its_aid_CAM, { bitmapSsp := PX_INNER_AT_CERTFICATE_BITMAP_SSP_CAM })),
        valueof(m_appPermissions(c_its_aid_DENM, { bitmapSsp := PX_INNER_AT_CERTFICATE_BITMAP_SSP_DENM }))
      };

      log(">>> f_generate_inner_at_request: p_enc_algo=", p_enc_algo);

      // Generate verification keys for the certificate to be requested
      if (f_generate_key_pair(p_private_key, v_public_key_x, v_public_key_y, p_public_key_compressed, p_compressed_key_mode) == false) {
        log("f_generate_inner_at_request: Failed to generate verification key");
        return false;
      }
      log ("f_generate_inner_at_request: AT verification private key: ", p_private_key);
      log ("f_generate_inner_at_request: AT verification public compressed key: ", p_public_key_compressed);
      log ("f_generate_inner_at_request: AT verification public compressed mode: ", p_compressed_key_mode);
      // Generate encryption keys for the certificate to be requested
      if (PX_INCLUDE_ENCRYPTION_KEYS) {
        if (f_generate_key_pair_for_encryption(p_enc_algo, p_private_enc_key, v_public_enc_key_x, v_public_enc_key_y, p_public_compressed_enc_key, p_compressed_enc_key_mode) == false) {
          log("f_generate_inner_at_request: Failed to generate encryption key");
          return false;
        } else {
          log ("f_generate_inner_at_request: AT encryption private key: ", p_private_enc_key);
          log ("f_generate_inner_at_request: AT encryption public compressed key: ", p_public_compressed_enc_key);
          log ("f_generate_inner_at_request: AT encryption public compressed mode: ", p_compressed_enc_key_mode);
        }
      } else {
        p_private_enc_key := ''O;
        v_public_enc_key_x := ''O;
        v_public_enc_key_y := ''O;
        p_public_compressed_enc_key := ''O;
        p_compressed_enc_key_mode := -1;
      }
      
      // Generate 32 octets length secret key
      v_hmac_key := f_hashWithSha256(int2oct((f_getCurrentTimeUtc() * 1000), 12));
      log("f_generate_inner_at_request: v_hmac_key= ", v_hmac_key);

      // Generate tag based on the concatenation of verification keys & encryption keys
      if (f_generate_key_tag(p_public_key_compressed, p_compressed_key_mode, p_public_compressed_enc_key, p_compressed_enc_key_mode, v_encoded_tag) == false) {
        log("f_generate_inner_at_request: Failed to generate Key tag");
        return false;
      }
      log("f_generate_inner_at_request: v_encoded_tag= ", v_encoded_tag);
      v_key_tag := substr(
                          fx_hmac_sha256( // TODO Rename and use a wrapper function
                                         v_hmac_key,
                                         v_encoded_tag
                                         ),
                          0,
                          16); // Leftmost 128 bits of the HMAC-SHA256 tag computed previously
      log("f_generate_inner_at_request: v_key_tag= ", v_key_tag);

      // Build the SharedAtRequest
      p_inner_at_request.sharedAtRequest := valueof(
                                                    m_shared_at_request(
                                                                        p_ea_hashed_id8, // eaId identifies the EA certificate shared with EA entity
                                                                        v_key_tag, // Calculated keyTag
                                                                        valueof(
                                                                                m_certificate_subject_attributes( // FIXME Review subjectPermissions
                                                                                                                 v_appPermissions,
                                                                                                                 p_ec_certificate.toBeSigned.certRequestPermissions,
                                                                                                                 -,//{ none_ := NULL },//p_ec_certificate.toBeSigned.id,
                                                                                                                 p_ec_certificate.toBeSigned.validityPeriod,
                                                                                                                 p_ec_certificate.toBeSigned.region,
                                                                                                                 p_ec_certificate.toBeSigned.assuranceLevel
                                                                                                                  ))) // Desired attributes
                                                    );
      
      // Calculate the hash of the SharedAtRequest
      v_hash_shared_at_request := f_hashWithSha256(bit2oct(encvalue(p_inner_at_request.sharedAtRequest)));
      log("f_generate_inner_at_request: v_hash_shared_at_request= ", v_hash_shared_at_request);
      
      // Build the ETsiTs103097Data-SignedExternalPayload
      v_tbs := m_toBeSignedData(
                                m_signedDataPayload_ext(v_hash_shared_at_request), // Payload containing extDataHash
                                m_headerInfo_inner_pki_request( // HeaderInfo
                                                               -,
                                                               (f_getCurrentTime()) * 1000) //us
                               );
      log("f_generate_inner_at_request: v_tbs= ", v_tbs);
      
      // Calculate the whole certificate SHA
      v_enc_value := encvalue(p_ec_certificate);
      if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP384r1)) {
        v_ec_hash := f_hashWithSha384(bit2oct(v_enc_value));
        v_ec_hashed_id8 := f_hashedId8FromSha384(v_ec_hash);
      } else {
        v_ec_hash := f_hashWithSha256(bit2oct(v_enc_value));
        v_ec_hashed_id8 := f_hashedId8FromSha256(v_ec_hash);
      }
      log("f_generate_inner_at_request: v_ec_hash= ", v_ec_hash);
      
      // Signed ToBeSigned payload using the private key of EC certificate obtained from Enrolment request
      // In case of ITS-S privacy, v_signed_at_signature contained the data to be encrypted
      if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP384r1)) {
        v_hashId := sha384;
        v_tbs_signed := f_signWithEcdsaBrainpoolp384r1WithSha384(bit2oct(encvalue(v_tbs)), v_ec_hash, p_ec_private_key);
        v_signature := valueof(
                               m_signature_ecdsaBrainpoolP384r1(
                                                                m_ecdsaP384Signature(
                                                                                     m_eccP384CurvePoint_x_only(
                                                                                                                substr(v_tbs_signed, 0, 48)
                                                                                                                ),
                                                                                     substr(v_tbs_signed, 48, 48)
                                                                                     )
                                                                )
                                                        );
      } else {
        v_hashId := sha256;
        if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1)) {
          v_tbs_signed := f_signWithEcdsaBrainpoolp256r1WithSha256(bit2oct(encvalue(v_tbs)), v_ec_hash, p_ec_private_key);
          v_signature := valueof(
                                 m_signature_ecdsaBrainpoolP256r1(
                                                                  m_ecdsaP256Signature(
                                                                                       m_eccP256CurvePoint_x_only(
                                                                                                                  substr(v_tbs_signed, 0, 32)
                                                                                                                  ),
                                                                                       substr(v_tbs_signed, 32, 32)
                                                                                       )
                                                                  )
                                 );
        } else if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256)) {
          v_tbs_signed := f_signWithEcdsaNistp256WithSha256(bit2oct(encvalue(v_tbs)), v_ec_hash, p_ec_private_key);
          v_signature := valueof(
                                 m_signature_ecdsaNistP256(
                                                           m_ecdsaP256Signature(
                                                                                m_eccP256CurvePoint_x_only(
                                                                                                           substr(v_tbs_signed, 0, 32)
                                                                                                           ),
                                                                                substr(v_tbs_signed, 32, 32)
                                                                                )
                                                           )
                                 );
        } else {
          // Error
          log("f_generate_inner_at_request: Failed to process signature");
          return false;
        }
      }
      v_signed_at_signature := valueof(
                                       m_etsiTs103097Data_signed(
                                                                 m_signedData(
                                                                              v_hashId,
                                                                              v_tbs,
                                                                              m_signerIdentifier_digest(v_ec_hashed_id8), // Signer is the hasheId8 of the EC certificate obtained from Enrolment request
                                                                              v_signature
                                                                              )
                                                                 )
                                       );
      log("f_generate_inner_at_request: v_signed_at_signature= ", v_signed_at_signature);
      log("f_generate_inner_at_request: p_ea_certificate= ", p_ea_certificate);
      
      if (PICS_ITS_S_WITH_PRIVACY) { // Build EtsiTs102097Data-Encrypted structure
        var octetstring v_public_enc_key;
        var integer v_compressed_mode;
        var Oct12 v_nonce;
        var Oct16 v_authentication_vector;
        var Oct16 v_aes_sym_key;
        var Oct16 v_encrypted_sym_key;
        var HashedId8 v_recipientId;
        var octetstring v_public_compressed_ephemeral_key;
        var integer v_public_compressed_ephemeral_mode;
        var octetstring v_enc_signed_ec_signature;
        var EncryptedDataEncryptionKey v_encrypted_data_encryption_key;
        
        // Use EA certificate for the encryption
        if (p_enc_algo == e_nist_p256) {
          if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_0)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_0;
            v_compressed_mode := 0;
          } else if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_1)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_1;
            v_compressed_mode := 1;
          } else {
            log("f_generate_inner_at_request: Wrong NistP256 encryption variant");
            return false;
          }
          v_enc_signed_ec_signature := f_encryptWithEciesNistp256WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce);
          if (v_public_compressed_ephemeral_mode == 0) {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_compressed_ephemeral_key));
          } else {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_compressed_ephemeral_key));
          }
          v_encrypted_data_encryption_key := valueof(
                                                     m_encryptedDataEncryptionKey_eciesNistP256(
                                                                                                m_evciesP256EncryptedKey(
                                                                                                                         v_eccP256_curve_point,
                                                                                                                         v_encrypted_sym_key,
                                                                                                                         v_authentication_vector
                                                                                                                         )));
        } else if (p_enc_algo == e_brainpool_p256_r1) {
          if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_0)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_0;
            v_compressed_mode := 0;
          } else if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_1)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_1;
            v_compressed_mode := 1;
          } else {
            log("f_generate_inner_at_request: Wrong BrainpoolP256r1 encryption variant");
            return false;
          }
          v_enc_signed_ec_signature := f_encryptWithEciesBrainpoolp256r1WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce);
          if (v_public_compressed_ephemeral_mode == 0) {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_compressed_ephemeral_key));
          } else {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_compressed_ephemeral_key));
          }
          v_encrypted_data_encryption_key := valueof(
                                                     m_encryptedDataEncryptionKey_eciesBrainpoolP256r1(
                                                                                                       m_evciesP256EncryptedKey(
                                                                                                                                v_eccP256_curve_point,
                                                                                                                                v_encrypted_sym_key,
                                                                                                                                v_authentication_vector
                                                                                                                                )));
        } else {
          log("f_generate_inner_at_request: Wrong encryption variant");
          return false;
        }
        log("f_generate_inner_at_request: v_encrypted_data_encryption_key= ", v_encrypted_data_encryption_key);
        v_recipientId := p_ea_hashed_id8; // RecipientId is the HashedId8 of the EA certificate
        log("f_generate_inner_at_request: v_recipientId= ", v_recipientId);
        // Fill Certificate template with the public compressed keys (canonical form)
        p_inner_at_request.ecSignature := valueof(
                                                  m_ec_signature(
                                                                 m_etsiTs103097Data_encrypted(
                                                                                              m_encryptedData(
                                                                                                              {
                                                                                                                m_recipientInfo_certRecipInfo(
                                                                                                                                              m_pKRecipientInfo(
                                                                                                                                                                v_recipientId,
                                                                                                                                                                
                                                                                                                                                                v_encrypted_data_encryption_key                                                                                                                                                            ))
                                                                                                                },
                                                                                                              m_symmetricCiphertext_aes128ccm(
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                              m_aesCcmCiphertext(
                                                                                                                                                                 v_nonce,
                                                                                                                                                                 v_enc_signed_ec_signature
                                                                                                                                                                 )
                                                                                                                                              )
                                                                                                              )
                                                                                              )
                                                                 )
                                                  );
      } else { // Skip the encryption, alowed to be re-identified by the AA
        p_inner_at_request.ecSignature := valueof(m_ec_signature_ext_payload(v_signed_at_signature));
      }
      // Build the InnerAtRequest, EcSignature field is already set
      if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256)) {
        if (p_compressed_key_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_key_x));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_key_x));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaNistP256(v_eccP256_curve_point));
      } else if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1)) {
        if (p_compressed_key_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_key_x));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_key_x));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP256r1(v_eccP256_curve_point));
      } else {
        var EccP384CurvePoint v_eccP384_curve_point;
        if (p_compressed_key_mode == 0) {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_0(v_public_key_x));
        } else {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_1(v_public_key_x));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP384r1(v_eccP384_curve_point));
      }
      if (PX_INCLUDE_ENCRYPTION_KEYS) {
        var template (value) EccP256CurvePoint v_enc_eccP256_curve_point;
        
        if (p_compressed_enc_key_mode == 0) {
          v_enc_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_0(v_public_enc_key_x);
        } else {
          v_enc_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_1(v_public_enc_key_x);
        }
        if (p_enc_algo == e_nist_p256) {
          v_public_encryption_key := valueof(m_publicEncryptionKey_eciesNistP256(v_enc_eccP256_curve_point));
        } else {
          v_public_encryption_key := valueof(m_publicEncryptionKey_eciesBrainpoolP256r1(v_enc_eccP256_curve_point));
        }
        p_inner_at_request.publicKeys := valueof( // The freshly generated public verification & encrypition keys to be used for the requested AT certificate
                                                 m_publicKeys(
                                                              v_public_verification_key,
                                                              m_encryptionKey( // FIXME Encryption keys could be optional
                                                                              -,
                                                                              v_public_encryption_key
                                                                              )
                                                              )
                                                  );
      } else {
        p_inner_at_request.publicKeys := valueof( // The freshly generated public verification keys to be used for the requested AT certificate
                                                 m_publicKeys(
                                                              v_public_verification_key
                                                              )
                                                  );
      }
      p_inner_at_request.hmacKey := v_hmac_key;
      log("f_generate_inner_at_request: p_inner_at_request= ", p_inner_at_request);
      
      return true;
    } // End of function f_generate_inner_at_request
    
    function f_generate_inner_at_request_with_wrong_parameters(
                                                               in Certificate p_aa_certificate,
                                                               in SignAlgorithm p_enc_algo := PX_EC_ALG_FOR_AT,
ASN.1 Documenter's avatar
ASN.1 Documenter committed
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018
                                                               in Oct8 p_aa_hashed_id8,
                                                               in Certificate p_ea_certificate,
                                                               in octetstring p_salt,
                                                               in Oct8 p_ea_hashed_id8,
                                                               in Certificate p_ec_certificate,
                                                               in octetstring p_ec_private_key,
                                                               in boolean p_alter_hmac := false,
                                                               in boolean p_alter_signer_digest := false,
                                                               in template (omit) Time32 p_start := omit,
                                                               in template (omit) Duration p_duration := omit,
                                                               in template (omit) Time64 p_generation_time := omit,
                                                               out octetstring p_private_key,
                                                               out octetstring p_public_key_compressed,
                                                               out integer p_compressed_key_mode,
                                                               out octetstring p_private_enc_key,
                                                               out octetstring p_public_compressed_enc_key,
                                                               out integer p_compressed_enc_key_mode,
                                                               out InnerAtRequest p_inner_at_request
                                                               ) return boolean {
      // Local variables
      var octetstring v_public_key_x;
      var octetstring v_public_key_y;
      var octetstring v_public_enc_key_x;
      var octetstring v_public_enc_key_y;
      var bitstring v_enc_value;
      var octetstring v_ec_hash;
      var PublicVerificationKey v_public_verification_key;
      var BasePublicEncryptionKey v_public_encryption_key;
      var Oct8 v_ec_hashed_id8;
      var octetstring public_enc_key_x;
      var octetstring public_enc_key_y;
      var Oct32 v_hmac_key;
      var PublicVerificationKey v_verification_tag;
      var PublicEncryptionKey v_encryption_tag;
      var octetstring v_encoded_tag;
      var Oct16 v_key_tag;
      var octetstring v_hash_shared_at_request;
      var template (value) ToBeSignedData v_tbs;
      var octetstring v_tbs_signed;
      var Ieee1609Dot2Data v_signed_at_signature;
      var template (value) EccP256CurvePoint v_eccP256_curve_point;
      var template (value) EccP256CurvePoint v_enc_eccP256_curve_point;
      var HashAlgorithm v_hashId;
      var Signature v_signature;
      var Time32 v_start;
      var Duration v_duration;
      var SequenceOfPsidSsp v_appPermissions := { // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs
        valueof(m_appPermissions(c_its_aid_CAM, { bitmapSsp := PX_INNER_AT_CERTFICATE_BITMAP_SSP_CAM })),
        valueof(m_appPermissions(c_its_aid_DENM, { bitmapSsp := PX_INNER_AT_CERTFICATE_BITMAP_SSP_DENM }))
        };

      log("f_generate_inner_at_request_with_wrong_parameters: p_enc_algo=", p_enc_algo);

      // Generate verification keys for the certificate to be requested
      if (f_generate_key_pair(p_private_key, v_public_key_x, v_public_key_y, p_public_key_compressed, p_compressed_key_mode) == false) {
        log("f_generate_inner_at_request_with_wrong_parameters: Failed to generate verification key");
        return false;
      }
      log ("f_generate_inner_at_request_with_wrong_parameters: AT verification private key: ", p_private_key);
      log ("f_generate_inner_at_request_with_wrong_parameters: AT verification public compressed key: ", p_public_key_compressed);
      log ("f_generate_inner_at_request_with_wrong_parameters: AT verification public compressed mode: ", p_compressed_key_mode);
      // Generate encryption keys for the certificate to be requested
      if (PX_INCLUDE_ENCRYPTION_KEYS) {
        if (f_generate_key_pair_for_encryption(p_enc_algo, p_private_enc_key, v_public_enc_key_x, v_public_enc_key_y, p_public_compressed_enc_key, p_compressed_enc_key_mode) == false) {
          log("f_generate_inner_at_request_with_wrong_parameters: Failed to generate encryption key");
          return false;
        } else {
          log ("f_generate_inner_at_request_with_wrong_parameters: AT encryption private key: ", p_private_enc_key);
          log ("f_generate_inner_at_request_with_wrong_parameters: AT encryption public compressed key: ", p_public_compressed_enc_key);
          log ("f_generate_inner_at_request_with_wrong_parameters: AT encryption public compressed mode: ", p_compressed_enc_key_mode);
        }
      } else {
        p_private_enc_key := ''O;
        v_public_enc_key_x := ''O;
        v_public_enc_key_y := ''O;
        p_public_compressed_enc_key := ''O;
        p_compressed_enc_key_mode := -1;
      }
      
      // Calculate the whole certificate SHA
      v_enc_value := encvalue(p_ec_certificate);
      if (ischosen(p_ec_certificate.issuer.sha256AndDigest)) {
        v_ec_hash := f_hashWithSha256(bit2oct(v_enc_value));
        v_ec_hashed_id8 := f_hashedId8FromSha256(v_ec_hash);
      } else {
        v_ec_hash := f_hashWithSha384(bit2oct(v_enc_value));
        v_ec_hashed_id8 := f_hashedId8FromSha384(v_ec_hash);
      }
      log("f_generate_inner_at_request_with_wrong_parameters: v_ec_hash= ", v_ec_hash);
      log("f_generate_inner_at_request_with_wrong_parameters: v_ec_hashed_id8= ", v_ec_hashed_id8);
      if (p_alter_signer_digest == true) {
        v_ec_hashed_id8 := int2oct((f_getCurrentTimeUtc() * 1000), 8);
        log("f_generate_inner_at_request_with_wrong_parameters: Altered v_ec_hashed_id8= ", v_ec_hashed_id8);
      }
      
      // Generate 32 octets length secret key
      v_hmac_key := f_hashWithSha256(int2oct((f_getCurrentTimeUtc() * 1000), 12));
      log("f_generate_inner_at_request_with_wrong_parameters: v_hmac_key= ", v_hmac_key);

      // Generate tag based on the concatenation of verification keys & encryption keys
      if (f_generate_key_tag(p_public_key_compressed, p_compressed_key_mode, p_public_compressed_enc_key, p_compressed_enc_key_mode, v_encoded_tag) == false) {
        log("f_generate_inner_at_request_with_wrong_parameters: Failed to generate Key tag");
        return false;
      }
      log("f_generate_inner_at_request_with_wrong_parameters: v_encoded_tag= ", v_encoded_tag);
      // Generate hmac key
      v_key_tag := substr(
                          fx_hmac_sha256( // TODO Rename and use a wrapper function
                                         v_hmac_key,
                                         v_encoded_tag
                                         ),
                          0,
                          16); // Leftmost 128 bits of the HMAC-SHA256 tag computed previously
      log("f_generate_inner_at_request_with_wrong_parameters: v_key_tag= ", v_key_tag);
      if (p_alter_hmac == true) {
        v_hmac_key[0] := 'aa'O;
        v_hmac_key[1] := 'bb'O;
        log("f_generate_inner_at_request_with_wrong_parameters: Altered key_tag= ", v_hmac_key);
      }
      
      // Build the SharedAtRequest
      if (not(ispresent(p_start))) {
        v_start := p_ec_certificate.toBeSigned.validityPeriod.start_;
      } else {
        v_start := valueof(p_start);
        log("f_generate_inner_at_request_with_wrong_parameters: Altered ValidityPeriod.start= ", v_start);
      }
      if (not(ispresent(p_duration))) {
        v_duration := p_ec_certificate.toBeSigned.validityPeriod.duration;
      } else {
        v_duration := valueof(p_duration);
        log("f_generate_inner_at_request_with_wrong_parameters: Altered ValidityPeriod.duration= ", v_duration);
      }
      p_inner_at_request.sharedAtRequest := valueof(
                                                    m_shared_at_request(
                                                                        p_ea_hashed_id8, // eaId identifies the EA certificate shared with EA entity
                                                                        v_key_tag, // Calculated keyTag
                                                                        valueof(
                                                                                m_certificate_subject_attributes(
                                                                                                                 v_appPermissions,
                                                                                                                 p_ec_certificate.toBeSigned.certRequestPermissions,
                                                                                                                 { none_ := NULL },//p_ec_certificate.toBeSigned.id,
                                                                                                                 m_validityPeriod(v_start, v_duration),
                                                                                                                 p_ec_certificate.toBeSigned.region,
                                                                                                                 p_ec_certificate.toBeSigned.assuranceLevel
                                                                                                                 ))) // Desired attributes
                                                    );
      
      // Calculate the hash of the SharedAtRequest
      v_hash_shared_at_request := f_hashWithSha256(bit2oct(encvalue(p_inner_at_request.sharedAtRequest)));
      log("f_generate_inner_at_request_with_wrong_parameters: v_hash_shared_at_request= ", v_hash_shared_at_request);
      
      // Build the ETsiTs103097Data-SignedExternalPayload
      if (ispresent(p_generation_time)) {
        v_tbs := m_toBeSignedData(
                                  m_signedDataPayload_ext(v_hash_shared_at_request), // Payload containing extDataHash
                                  m_headerInfo_inner_pki_request( // HeaderInfo
                                                                 -,
                                                                 valueof(p_generation_time) * 1000) //us
                                  );
        log("f_generate_inner_at_request_with_wrong_parameters: Altered generation time: v_tbs= ", v_tbs);
      } else {
        v_tbs := m_toBeSignedData(
                                  m_signedDataPayload_ext(v_hash_shared_at_request), // Payload containing extDataHash
                                  m_headerInfo_inner_pki_request( // HeaderInfo
                                                                 -,
                                                                 f_getCurrentTime() * 1000) //us
                                  );
        log("f_generate_inner_at_request_with_wrong_parameters: v_tbs= ", v_tbs);
      }
      // Signed ToBeSigned payload using the private key of EC certificate obtained from Enrolment request
      // In case of ITS-S privacy, v_signed_at_signature contained the data to be encrypted
      // TODO Simplify with f_signWithEcdsa
      if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP384r1)) {
        v_hashId := sha384;
        v_tbs_signed := f_signWithEcdsaBrainpoolp384r1WithSha384(bit2oct(encvalue(v_tbs)), v_ec_hash, p_ec_private_key);
        v_signature := valueof(
                               m_signature_ecdsaBrainpoolP384r1(
                                                                m_ecdsaP384Signature(
                                                                                     m_eccP384CurvePoint_x_only(
                                                                                                                substr(v_tbs_signed, 0, 48)
                                                                                                                ),
                                                                                     substr(v_tbs_signed, 48, 48)
                                                                                     )
                                                                )
                                                        );
      } else {
        v_hashId := sha256;
        if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1)) {
          v_tbs_signed := f_signWithEcdsaBrainpoolp256r1WithSha256(bit2oct(encvalue(v_tbs)), v_ec_hash, p_ec_private_key);
          v_signature := valueof(
                                 m_signature_ecdsaBrainpoolP256r1(
                                                                  m_ecdsaP256Signature(
                                                                                       m_eccP256CurvePoint_x_only(
                                                                                                                  substr(v_tbs_signed, 0, 32)
                                                                                                                  ),
                                                                                       substr(v_tbs_signed, 32, 32)
                                                                                       )
                                                                  )
                                 );
        } else if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256)) {
          v_tbs_signed := f_signWithEcdsaNistp256WithSha256(bit2oct(encvalue(v_tbs)), v_ec_hash, p_ec_private_key);
          v_signature := valueof(
                                 m_signature_ecdsaNistP256(
                                                           m_ecdsaP256Signature(
                                                                                m_eccP256CurvePoint_x_only(
                                                                                                           substr(v_tbs_signed, 0, 32)
                                                                                                           ),
                                                                                substr(v_tbs_signed, 32, 32)
                                                                                )
                                                           )
                                 );
        } else {
          // Error
          log("f_generate_inner_at_request_with_wrong_parameters: Failed to process signature");
          return false;
        }
      }
      v_signed_at_signature := valueof(
                                       m_etsiTs103097Data_signed(
                                                                 m_signedData(
                                                                              v_hashId,
                                                                              v_tbs,
                                                                              m_signerIdentifier_digest(v_ec_hashed_id8), // Signer is the hasheId8 of the EC certificate obtained from Enrolment request
                                                                              v_signature
                                                                              )
                                                                 )
                                       );
      log("f_generate_inner_at_request_with_wrong_parameters: v_signed_at_signature= ", v_signed_at_signature);
      
      if (PICS_ITS_S_WITH_PRIVACY) { // Build EtsiTs102097Data-Encrypted structure
        var octetstring v_public_enc_key;
        var integer v_compressed_mode;
        var Oct12 v_nonce;
        var Oct16 v_authentication_vector;
        var Oct16 v_aes_sym_key;
        var Oct16 v_encrypted_sym_key;
        var HashedId8 v_recipientId;
        var octetstring v_public_compressed_ephemeral_key;
        var integer v_public_compressed_ephemeral_mode;
        var octetstring v_enc_signed_ec_signature;
        var EncryptedDataEncryptionKey v_encrypted_data_encryption_key;
        
        // Use EA certificate for the encryption
        if (p_enc_algo == e_nist_p256) {
          if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_0)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_0;
            v_compressed_mode := 0;
          } else if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_1)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_1;
            v_compressed_mode := 1;
          } else {
            log("f_generate_inner_at_request_with_wrong_parameters: Wrong NistP256 encryption variant");
            return false;
          }
          v_enc_signed_ec_signature := f_encryptWithEciesNistp256WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce);
          if (v_public_compressed_ephemeral_mode == 0) {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_compressed_ephemeral_key));
          } else {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_compressed_ephemeral_key));
          }
          v_encrypted_data_encryption_key := valueof(
                                                     m_encryptedDataEncryptionKey_eciesNistP256(
                                                                                                m_evciesP256EncryptedKey(
                                                                                                                         v_eccP256_curve_point,
                                                                                                                         v_encrypted_sym_key,
                                                                                                                         v_authentication_vector
                                                                                                                         )));
        } else if (p_enc_algo == e_brainpool_p256_r1) {
          if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_0)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_0;
            v_compressed_mode := 0;
          } else if (ischosen(p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_1)) {
            v_public_enc_key := p_ea_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_1;
            v_compressed_mode := 1;
          } else {
            log("f_generate_inner_at_request_with_wrong_parameters: Wrong BrainpoolP256r1 encryption variant");
            return false;
          }
          v_enc_signed_ec_signature := f_encryptWithEciesBrainpoolp256r1WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce);
          if (v_public_compressed_ephemeral_mode == 0) {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_compressed_ephemeral_key));
          } else {
            v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_compressed_ephemeral_key));
          }
          v_encrypted_data_encryption_key := valueof(
                                                     m_encryptedDataEncryptionKey_eciesBrainpoolP256r1(
                                                                                                       m_evciesP256EncryptedKey(
                                                                                                                                v_eccP256_curve_point,
                                                                                                                                v_encrypted_sym_key,
                                                                                                                                v_authentication_vector
                                                                                                                                )));
        } else {
          log("f_generate_inner_at_request_with_wrong_parameters: Wrong encryption variant");
          return false;
        }
        log("f_generate_inner_at_request_with_wrong_parameters: v_encrypted_data_encryption_key= ", v_encrypted_data_encryption_key);
        v_recipientId := p_ea_hashed_id8; // RecipientId is the HashedId8 of the EA certificate
        log("f_generate_inner_at_request_with_wrong_parameters: v_recipientId= ", v_recipientId);
        // Fill Certificate template with the public compressed keys (canonical form)
        p_inner_at_request.ecSignature := valueof(
                                                  m_ec_signature(
                                                                 m_etsiTs103097Data_encrypted(
                                                                                              m_encryptedData(
                                                                                                              {
                                                                                                                m_recipientInfo_certRecipInfo(
                                                                                                                                              m_pKRecipientInfo(
                                                                                                                                                                v_recipientId,
                                                                                                                                                                
                                                                                                                                                                v_encrypted_data_encryption_key                                                                                                                                                            ))
                                                                                                                },
                                                                                                              m_symmetricCiphertext_aes128ccm(
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                              m_aesCcmCiphertext(
                                                                                                                                                                 v_nonce,
                                                                                                                                                                 v_enc_signed_ec_signature
                                                                                                                                                                 )
                                                                                                                                              )
                                                                                                              )
                                                                                              )
                                                                 )
                                                  );
      } else { // Skip the encryption, alowed to be re-identified by the AA
        p_inner_at_request.ecSignature := valueof(m_ec_signature_ext_payload(v_signed_at_signature));
      }
      // Build the InnerAtRequest, EcSignature field is already set
      if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256)) {
        if (p_compressed_key_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_key_x));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_key_x));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaNistP256(v_eccP256_curve_point));
      } else if (ischosen(p_ec_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1)) {
        if (p_compressed_key_mode == 0) {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_key_x));
        } else {
          v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_key_x));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP256r1(v_eccP256_curve_point));
      } else {
        var EccP384CurvePoint v_eccP384_curve_point;
        if (p_compressed_key_mode == 0) {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_0(v_public_key_x));
        } else {
          v_eccP384_curve_point := valueof(m_eccP384CurvePoint_compressed_y_1(v_public_key_x));
        }
        v_public_verification_key := valueof(m_publicVerificationKey_ecdsaBrainpoolP384r1(v_eccP384_curve_point));
      }
      if (PX_INCLUDE_ENCRYPTION_KEYS) {
        if (p_compressed_enc_key_mode == 0) {
          v_enc_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_0(v_public_enc_key_x);
        } else {
          v_enc_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_1(v_public_enc_key_x);
        }
        if (p_enc_algo == e_nist_p256) {
          v_public_encryption_key := valueof(m_publicEncryptionKey_eciesNistP256(v_enc_eccP256_curve_point));
        } else {
          v_public_encryption_key := valueof(m_publicEncryptionKey_eciesBrainpoolP256r1(v_enc_eccP256_curve_point));
        }
        p_inner_at_request.publicKeys := valueof( // The freshly generated public verification & encrypition keys to be used for the requested AT certificate
                                                 m_publicKeys(
                                                              v_public_verification_key,
                                                              m_encryptionKey( // FIXME Encryption keys could be optional
                                                                              -,
                                                                              v_public_encryption_key
                                                                              )
                                                              )
                                                  );
      } else {
        p_inner_at_request.publicKeys := valueof( // The freshly generated public verification keys to be used for the requested AT certificate
                                                 m_publicKeys(
                                                              v_public_verification_key
                                                              )
                                                  );
      }
      p_inner_at_request.hmacKey := v_hmac_key;
      log("f_generate_inner_at_request_with_wrong_parameters: p_inner_at_request= ", p_inner_at_request);
      
      return true;
    } // End of function f_generate_inner_at_request_with_wrong_parameters
    
    function f_verify_inner_at_request_signed_for_pop(
                                                      in EtsiTs102941Data p_etsi_ts_102941_data,
                                                      in EtsiTs103097Certificate p_ec_certificate,
                                                      out InnerAtRequest p_inner_at_request
                                                      ) return boolean {
      var bitstring v_msg_bit;

      log(">>> f_verify_inner_at_request_signed_for_pop: p_etsi_ts_102941_data=", p_etsi_ts_102941_data);
      log(">>> f_verify_inner_at_request_signed_for_pop: p_ec_certificate=", p_ec_certificate);
      
      // 1. Extract content
      p_inner_at_request := p_etsi_ts_102941_data.content.authorizationRequest;

        // 2. Verify the InnerEcRequestSignedForPop signature
        // TODO
      
      log("<<< f_verify_inner_at_request_signed_for_pop: ", p_inner_at_request);
      return true;
    } // End of function f_verify_inner_at_request_signed_for_pop
    
    function f_generate_inner_at_response(
                                          in octetstring p_authorization_request_hash,
                                          in EtsiTs103097Certificate p_certificate,
                                          out InnerAtResponse p_authorization_response
                                          ) return boolean {
      // Local variables
      
      // Build the Proof of Possession InnerEcResponse
      p_authorization_response := valueof(
                                          m_innerAtResponse_ok(
                                                               substr(p_authorization_request_hash, 0, 16),
                                                               p_certificate
                                                               )
                                          );
      
      return true;
    } // End of function f_generate_inner_at_response
    
  } // End of group inner_at_xxx
  
  group dc {

    function f_build_dc(
                        in charstring p_rca_certificate_id,
                        out EtsiTs103097Certificate p_rca_certificate
                        ) {
      log(">>> f_build_dc");

      // Load certificate
      f_readCertificate(p_rca_certificate_id, p_rca_certificate);
    }
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    function f_verify_rca_ctl_response_message(
                                               in EtsiTs103097Data p_etsi_ts_103097_signed_data,
                                               in boolean p_check_security := true,
                                               out ToBeSignedRcaCtl p_to_be_signed_rca_ctl
                                               ) return boolean {
      var bitstring v_etsi_ts_102941_data_msg;
      var bitstring v_tbs;
      var Certificate v_certificate;
      var charstring v_certificate_id;
      var octetstring v_issuer;
      var EtsiTs102941Data v_etsi_ts_102941_data;

      log(">>> f_verify_rca_ctl_response_message: p_etsi_ts_103097_signed_data= ", p_etsi_ts_103097_signed_data);

      // 1. Verify signature
      log("f_verify_rca_ctl_response_message: p_etsi_ts_103097_signed_data.content.signedData.tbsData= ", p_etsi_ts_103097_signed_data.content.signedData.tbsData);
      v_tbs := encvalue(p_etsi_ts_103097_signed_data.content.signedData.tbsData);
      if (ispresent(p_etsi_ts_103097_signed_data.content.signedData.signer.digest)) {
        if (f_getCertificateFromDigest(p_etsi_ts_103097_signed_data.content.signedData.signer.digest, v_certificate, v_certificate_id) == false) {
          log("f_verify_rca_ctl_response_message: Failed to retrieve certificate from ", p_etsi_ts_103097_signed_data.content.signedData.signer.digest);
          if (p_check_security == true) {
            return false;
          }
        }
        log("f_verify_rca_ctl_response_message (1): v_certificate: ", v_certificate);
        f_getCertificateHash(v_certificate_id, v_issuer);
      } else {
        v_certificate := p_etsi_ts_103097_signed_data.content.signedData.signer.certificate[0];
        log("f_verify_rca_ctl_response_message (2): v_certificate: ", v_certificate);
        if (ispresent(v_certificate.issuer.sha256AndDigest)) {
          v_issuer := v_certificate.issuer.sha256AndDigest;
        } if (ispresent(v_certificate.issuer.sha384AndDigest)) {
          v_issuer := v_certificate.issuer.sha384AndDigest;
        } else { // self_
          if (v_certificate.issuer.self_ == sha256) {
            v_issuer := int2oct(0, 32);
          } else {
            v_issuer := int2oct(0, 48);
          }
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        }
      }
      if (f_verifyEcdsa(bit2oct(v_tbs), v_issuer, p_etsi_ts_103097_signed_data.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey) == false) {
        log("f_verify_rca_ctl_response_message: Failed to verify signature");
        if (p_check_security == true) {
          return false;
        }
      }
      v_etsi_ts_102941_data_msg := oct2bit(p_etsi_ts_103097_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData);
      if (decvalue(v_etsi_ts_102941_data_msg, v_etsi_ts_102941_data) != 0) {
        log("f_verify_rca_ctl_response_message: Failed to decode EtsiTs102941Data");
        return false;
      } else {
        log("f_verify_rca_ctl_response_message: v_etsi_ts_102941_data= ", v_etsi_ts_102941_data);
        log("f_verify_pki_response_message: RcaCertificateTrustListMessage matching= ", match(v_etsi_ts_102941_data, mw_etsiTs102941Data_to_be_signed_rca_ctl));
        if (match(v_etsi_ts_102941_data, mw_etsiTs102941Data_to_be_signed_rca_ctl) == false) {
          log("f_verify_rca_ctl_response_message: Failed to decode certificateTrustListRca");
          return false;
        } else {
          var Time32 v_time := (f_getCurrentTime()/* - 1072915200000*/) / 1000;
          p_to_be_signed_rca_ctl := v_etsi_ts_102941_data.content.certificateTrustListRca;
          log("f_verify_rca_ctl_response_message: p_to_be_signed_rca_ctl= ", p_to_be_signed_rca_ctl);
          if (p_to_be_signed_rca_ctl.nextUpdate <= v_time) {
            log("f_verify_rca_ctl_response_message: Invalid nextUpdate value: compared values=", p_to_be_signed_rca_ctl.nextUpdate, "/", v_time);
            return false;
          }
          // TODO Verify RCA certificate & signature
        }
      }

      return true;
    }

    function f_verify_rca_crl_response_message(
                                               in EtsiTs103097Data p_etsi_ts_103097_signed_data,
                                               in boolean p_check_security := true,
                                               out ToBeSignedCrl p_to_be_signed_crl
                                               ) return boolean {
      var bitstring v_etsi_ts_102941_data_msg;
      var bitstring v_tbs;
      var Certificate v_certificate;
      var charstring v_certificate_id;
      var octetstring v_issuer;
      var EtsiTs102941Data v_etsi_ts_102941_data;

      log(">>> f_verify_rca_crl_response_message: p_etsi_ts_103097_signed_data= ", p_etsi_ts_103097_signed_data);

      // 1. Verify signature
      log("f_verify_rca_crl_response_message: p_etsi_ts_103097_signed_data.content.signedData.tbsData= ", p_etsi_ts_103097_signed_data.content.signedData.tbsData);
      v_tbs := encvalue(p_etsi_ts_103097_signed_data.content.signedData.tbsData);
      if (f_getCertificateFromDigest(p_etsi_ts_103097_signed_data.content.signedData.signer.digest, v_certificate, v_certificate_id) == false) {
        log("f_verify_rca_crl_response_message: Failed to retrieve certificate from ", p_etsi_ts_103097_signed_data.content.signedData.signer.digest);
        if (p_check_security == true) {
          return false;
        }
      }
      f_getCertificateHash(v_certificate_id, v_issuer);
      if (f_verifyEcdsa(bit2oct(v_tbs), v_issuer, p_etsi_ts_103097_signed_data.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey) == false) {
        log("f_verify_rca_crl_response_message: Failed to verify signature");
        if (p_check_security == true) {
          return false;
        }
      }
      v_etsi_ts_102941_data_msg := oct2bit(p_etsi_ts_103097_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData);
      if (decvalue(v_etsi_ts_102941_data_msg, v_etsi_ts_102941_data) != 0) {
        log("f_verify_rca_crl_response_message: Failed to decode EtsiTs102941Data");
        return false;
      } else {
        log("f_verify_rca_crl_response_message: v_etsi_ts_102941_data= ", v_etsi_ts_102941_data);
        log("f_verify_pki_response_message: CertificateRevocationList matching= ", match(v_etsi_ts_102941_data, mw_etsiTs102941Data_to_be_signed_crl));
        if (match(v_etsi_ts_102941_data, mw_etsiTs102941Data_to_be_signed_crl) == false) {
          log("f_verify_rca_crl_response_message: Failed to decode certificateRevocationList");
          return false;
        } else {
          var Time32 v_time := (f_getCurrentTime()/* - 1072915200000*/) / 1000;
          p_to_be_signed_crl := v_etsi_ts_102941_data.content.certificateRevocationList;
          log("f_verify_rca_crl_response_message: p_to_be_signed_crl= ", p_to_be_signed_crl);
          if (p_to_be_signed_crl.thisUpdate >= v_time) {
            log("f_verify_rca_crl_response_message: Invalid thisUpdate value");
            return false;
          }
          if (p_to_be_signed_crl.nextUpdate <= v_time) {
            log("f_verify_rca_crl_response_message: Invalid nextUpdate value");
            return false;
          }
          // TODO Verify RCA certificate & signature
        }
      }

      return true;
    }

    /**
     * @desc this function is used to retrieve the root certificate from SubCA entity
     * @param p_certificate The root certificate
     * @return 0 on success, -1 otherwise
     */
    function f_get_root_ca_certificate(
                                       in charstring p_iut_certificate := "CERT_IUT_A_CA",
                                       in boolean p_explicit_type := false,
                                       out Certificate p_certificate
                                       ) runs on ItsPkiHttp return integer {
      var Headers v_headers;
      var HttpMessage v_response;
      var octetstring v_os;
      var bitstring v_msg_bit;
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      log(">>> f_get_root_ca_certificate");
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      // Get root certificate
      f_cfHttpUp_ca();
      f_init_default_headers_list(PICS_HEADER_CTL_CONTENT_TYPE, "ca_request", v_headers);
      // Test Body
      f_http_send(
                  v_headers,
                  m_http_request(
                                  m_http_request_get(
                                                    PICS_HTTP_GET_URI_DC,
                                                    v_headers
                                                    )));
      tc_ac.start;
      alt {
        [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(
                                                        mw_http_response(
                                                                          mw_http_response_ok(
                                                                                              mw_http_message_body_binary(
                                                                                                                          mw_binary_body_ieee1609dot2_certificate
                                                                                                                          )))) -> value v_response {
          tc_ac.stop;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        }
        [PICS_MULTIPLE_END_POINT] httpCaPort.receive(
                                                      mw_http_response(
                                                                      mw_http_response_ok(
                                                                                          mw_http_message_body_binary(
                                                                                                                      mw_binary_body_ieee1609dot2_certificate
                                                                                                                      )))) -> value v_response {
          tc_ac.stop;
        }
        [] tc_ac.timeout {
        }
      } // End of 'alt' statement
      f_cfHttpDown_ca();
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      if (not(isvalue(v_response))) {
        log("f_get_root_ca_certificate: fail to get certificate");
        return -1;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      }
      log("v_response.response.body.binary_body.ieee1609dot2_certificate: ", v_response.response.body.binary_body.ieee1609dot2_certificate);
      p_certificate := v_response.response.body.binary_body.ieee1609dot2_certificate;
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      log("<<< f_get_root_ca_certificate: ", p_certificate);
      return 0;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    }

    function f_verify_rca_certificate(
                                      in charstring p_authorized_certificate := "CERT_IUT_A_RCA",//"CERT_IUT_A_RCA",
                                      in Certificate p_certificate,
                                      in boolean p_check_implicit := false,
                                      in boolean p_check_reconstruction_value := false,
                                      in boolean p_check_no_signature := false,
                                      in boolean p_check_region_restriction := false,
                                      in boolean p_check_signature_content := false,
                                      in boolean p_check_app_permissions := false,
                                      in boolean p_check_app_ssps := false,
                                      in boolean p_check_app_validity_period := false
                                      ) return boolean {
      var CertificateType v_type_ := explicit;
      var template Signature v_signature_ := ?;
      var template IssuerIdentifier v_issuer := ?;
      var template PublicVerificationKey v_public_verification_key := ?;
ASN.1 Documenter's avatar
ASN.1 Documenter committed

      log(">>> f_verify_rca_certificate: p_authorized_certificate= ", p_authorized_certificate);
      log(">>> f_verify_rca_certificate: p_certificate= ", p_certificate);

      if (p_check_implicit == true) {
        v_type_ := implicit;
      }
      if (p_check_no_signature == true) {
        v_signature_ := omit;
      }
      if (match(p_certificate, mw_etsiTs103097Certificate(-, -, v_signature_, v_type_)) == false) {
        log("f_verify_rca_certificate: version/explicit mismatch");
        return false;
      }
      if (p_check_reconstruction_value == false) {
        if (match(p_certificate, mw_etsiTs103097Certificate(
                                                            -,
                                                            mw_toBeSignedCertificate_ca(
                                                                                        (mw_certificateId_none, mw_certificateId_name),
                                                                                        -,
                                                                                        -,
                                                                                        mw_verificationKeyIndicator_verificationKey
                                                                                        ),
                                                            v_signature_
                                                            )) == false) {
          log("f_verify_rca_certificate: verificationKey mismatch");
          return false;
        }
        if (p_check_signature_content) {
          var template PublicVerificationKey v_publicVerificationKey;
          
          if (PICS_SEC_SHA256) {
            v_signature_ := mw_signature_ecdsaNistP256;
            v_issuer := (mw_issuerIdentifier_self(sha256), mw_issuerIdentifier_sha256AndDigest);
            v_public_verification_key := mw_publicVerificationKey_ecdsaNistP256;
          } else if (PICS_SEC_BRAINPOOL_P256R1) {
            v_signature_ := mw_signature_ecdsaBrainpoolP256r1;
            v_issuer := (mw_issuerIdentifier_self(sha256), mw_issuerIdentifier_sha256AndDigest);
            v_public_verification_key := mw_publicVerificationKey_ecdsaBrainpoolP256r1;
          } else if (PICS_SEC_BRAINPOOL_P384R1) {
            v_signature_ := mw_signature_ecdsaBrainpoolP384r1;
            v_issuer := (mw_issuerIdentifier_self(sha384), mw_issuerIdentifier_sha384AndDigest);
            v_public_verification_key := mw_publicVerificationKey_ecdsaBrainpoolP384r1;
          }
          if (match(p_certificate, mw_etsiTs103097Certificate(
                                                              v_issuer,
                                                              mw_toBeSignedCertificate_ca(
                                                                                          (mw_certificateId_none, mw_certificateId_name),
                                                                                          -,
                                                                                          -,
                                                                                          mw_verificationKeyIndicator_verificationKey(v_public_verification_key),
                                                                                          -, -, -, -,
                                                                                          -//mw_encryptionKey
                                                                                          ),
                                                              v_signature_
                                                              )) == false) {
            log("f_verify_rca_certificate: signature mismatch");
            return false;
          }
          // Verify Signature
          if (ischosen(p_certificate.issuer.self_)) {
            v_publicVerificationKey := p_certificate.toBeSigned.verifyKeyIndicator.verificationKey;
          } else {
            var HashedId8 v_digest;
            var Certificate v_authorized_certificate;
            var charstring v_cert;
            
            if (ischosen(p_certificate.issuer.sha256AndDigest)) {
              v_digest := p_certificate.issuer.sha256AndDigest;
            } else if (ischosen(p_certificate.issuer.sha384AndDigest)) {
              v_digest := p_certificate.issuer.sha384AndDigest;
            } else {
              log("f_verify_rca_certificate: Invalid certificate issuer ", p_certificate.issuer);
              return false;
            }
            if (f_getCertificateFromDigest(v_digest, v_authorized_certificate, v_cert) == false) {
              log("f_verify_rca_certificate: Fail to load p_authorized_certificate");
              return false;
            }
            v_publicVerificationKey := v_authorized_certificate.toBeSigned.verifyKeyIndicator.verificationKey
          }
          log("f_verify_rca_certificate: v_publicVerificationKey= ", v_publicVerificationKey);
          if (f_verifyCertificateSignatureWithPublicKey(p_certificate, v_publicVerificationKey) == false) {
            log("f_verify_rca_certificate: signature not verified");
            return false;
          }
        }
      } else {
        if (match(p_certificate, mw_etsiTs103097Certificate(
                                                            -,
                                                            mw_toBeSignedCertificate_ca(
                                                                                        (mw_certificateId_none, mw_certificateId_name),
                                                                                        -,
                                                                                        -,
                                                                                        mw_verificationKeyIndicator_reconstructionValue
                                                                                        ),
                                                            v_signature_
                                                            )) == false) {
          log("f_verify_rca_certificate: verificationKey mismatch");
          return false;
        }
        // TODO Verify Signature
      }

      if (p_check_region_restriction == true) {
        var Certificate v_authorized_certificate;
        var template GeographicRegion v_geographic_region := ?;

        if (f_readCertificate(p_authorized_certificate, v_authorized_certificate) == false) {
          log("f_verify_rca_certificate: Fail to load p_authorized_certificate");
          return false;
        }
        log("f_verify_rca_certificate: v_authorized_certificate=", v_authorized_certificate);

        if (PICS_SEC_CIRCULAR_REGION == true) {
          v_geographic_region := mw_geographicRegion_circle;
        } else if (PICS_SEC_RECTANGULAR_REGION == true) {
          v_geographic_region := mw_geographicRegion_rectangular;
        } else if (PICS_SEC_POLYGONAL_REGION == true) {
          v_geographic_region := mw_geographicRegion_polygonal;
        } else if (PICS_SEC_IDENTIFIED_REGION == true) {
        v_geographic_region := mw_geographicRegion_identified(
                                                              {
                                                                (mw_identifiedRegion_country_only, mw_identifiedRegion_country_and_region)
                                                                }
                                                              );
        }
        if (match(p_certificate, mw_etsiTs103097Certificate(
                                                            -,
                                                            mw_toBeSignedCertificate_ca(
                                                                                        -,
                                                                                        -,
                                                                                        -,
                                                                                        -,
                                                                                        -,
                                                                                        -,
                                                                                        v_geographic_region
                                                                                        )
                                                            )) == false) {
          log("f_verify_rca_certificate: Geographical region mismatch");
          return false;
        }
        // Check interception of area
        if (f_checkRegionValidityRestiction(v_authorized_certificate, p_certificate) == false) {
          log("f_verify_rca_certificate: Geographical region intersection mismatch");
          return false;
        }
      }
      // Check appPermissions
      if (p_check_app_permissions == true) {
        var integer v_idx, v_jdx;
        var charstring v_psid := ""; // 'psid' currently processed
        var charstring v_psidsFound := ";"; // Used to build the list of the 'psid' already processed
        var template charstring m_found_pattern; // Used in regex to verify that 'psid' was not found before
        var Certificate v_authorized_certificate;

        if (f_readCertificate(p_authorized_certificate, v_authorized_certificate) == false) {
          log("f_verify_rca_certificate: Fail to load p_authorized_certificate");
          return false;
        }
        log("f_verify_rca_certificate: v_authorized_certificate=", v_authorized_certificate);
        if (match(v_authorized_certificate.toBeSigned.certIssuePermissions, { mw_psidGroupPermissions }) == false) {
          log("f_verify_rca_certificate: eeType mismatch");
          return false;
        }

        for (v_idx := 0; v_idx < lengthof(p_certificate.toBeSigned.appPermissions); v_idx := v_idx + 1) {
          log("f_verify_rca_certificate: Processing ", p_certificate.toBeSigned.appPermissions[v_idx]);
          if (match(p_certificate.toBeSigned.appPermissions[v_idx], mw_appPermissions) == false) {
            log("f_verify_rca_certificate: PsidSsp mismatch");
            return false;
          }
          // Check uniqueness of PSIDs
          v_psid := int2str(p_certificate.toBeSigned.appPermissions[v_idx].psid);
          m_found_pattern := pattern "*({v_psid})*";
          if (regexp(v_psidsFound, m_found_pattern, 0) == v_psid) {
            log("f_verify_rca_certificate: Psid uniqueness is not verified");
            return false; // v_psid exist at least 2 times, uniqueness is not verified
          }
          // v_psid non found, add it into the built list
          v_psidsFound := v_psidsFound & v_psid & ";";
          // Check that 'psid' is in the certIssuePermissions component in the issuing certificate
          if (match(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions, mw_subjectPermissions_explicit) == false) {
            for (v_jdx := 0; v_jdx < lengthof(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit); v_jdx := v_jdx + 1) {
              if (int2str(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit[v_jdx].psid) == v_psid) {
                break;
              }
            } // End of 'for'statement
            if (v_jdx == lengthof(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit)) {
              log("f_verify_rca_certificate: Psid is not in the list of the issuing certificate");
              return false;
            }
          }
        } // End of 'for'statement
      }

      if (p_check_app_ssps == true) {
        var integer v_idx, v_jdx;
        var Certificate v_authorized_certificate;

        if (f_readCertificate(p_authorized_certificate, v_authorized_certificate) == false) {
          log("f_verify_rca_certificate: Fail to load p_authorized_certificate");
          return false;
        }
        log("f_verify_rca_certificate: v_authorized_certificate=", v_authorized_certificate);
        for (v_idx := 0; v_idx < lengthof(p_certificate.toBeSigned.appPermissions); v_idx := v_idx + 1) {
          log("f_verify_rca_certificate: Processing ", p_certificate.toBeSigned.appPermissions[v_idx]);
          if (match(p_certificate.toBeSigned.appPermissions[v_idx], mw_appPermissions(-, ?)) == false) {
            log("f_verify_rca_certificate: appPermissions mismatch");
            return false;
          }
          // Check that 'ssp' is in the certIssuePermissions component in the issuing certificate
          for (v_jdx := 0; v_jdx < lengthof(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit); v_jdx := v_jdx + 1) {
            log("f_verify_rca_certificate: compare psid ", v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit[v_jdx].psid, " - ", p_certificate.toBeSigned.appPermissions[v_idx].psid);
            if (v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit[v_jdx].psid == p_certificate.toBeSigned.appPermissions[v_idx].psid) {
              break;
            }
          } // End of 'for'statement
          if (v_jdx == lengthof(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit)) {
            log("f_verify_rca_certificate: Psid is not in the list of the issuing certificate");
            return false;
          } else {
            var BitmapSsp v_ssp_ca := substr(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit[v_jdx].sspRange.bitmapSspRange.sspValue, 1, -1 + lengthof(v_authorized_certificate.toBeSigned.certIssuePermissions[0].subjectPermissions.explicit[v_jdx].sspRange.bitmapSspRange.sspValue));
            log("f_verify_rca_certificate: v_ssp_ca= ", v_ssp_ca, " - ssp= ", p_certificate.toBeSigned.appPermissions[v_idx].ssp.bitmapSsp);
            if (v_ssp_ca != p_certificate.toBeSigned.appPermissions[v_idx].ssp.bitmapSsp) {
              log("f_verify_rca_certificate: SSPs mismatch: CA");
              return false;
            }
          }
        } // End of 'for'statement
      }

      if (p_check_app_validity_period == true) {
        var integer v_idx, v_jdx;
        var Certificate v_authorized_certificate;
        var UInt32 v_duration, v_duration_ca;

        if (f_readCertificate(p_authorized_certificate, v_authorized_certificate) == false) {
          log("f_verify_rca_certificate: Fail to load p_authorized_certificate");
          return false;
        }
        log("f_verify_rca_certificate: v_authorized_certificate=", v_authorized_certificate);
        // Check start date (indicating X_START_VALIDITY ( X_START_VALIDITY >= X_START_VALIDITY_CA ))
        if (p_certificate.toBeSigned.validityPeriod.start_ < v_authorized_certificate.toBeSigned.validityPeriod.start_) {
          log("f_verify_rca_certificate: validityPeriod.start_ mismatch");
          return false;
        }
        // Check duration (value <= X_START_VALIDITY_CA + X_DURATION_CA - X_START_VALIDITY)
        v_duration := duration_to_uint32(p_certificate.toBeSigned.validityPeriod.duration);
        v_duration_ca := duration_to_uint32(v_authorized_certificate.toBeSigned.validityPeriod.duration);
        if (v_duration > (v_authorized_certificate.toBeSigned.validityPeriod.start_ + v_duration_ca - p_certificate.toBeSigned.validityPeriod.start_)) {
          log("f_verify_rca_certificate: validityPeriod.duration mismatch");
          return false;
        }
      }
      
      return true;
    }

    function duration_to_uint32(
                                in Duration p_duration
                                ) return UInt32 {
      if (ischosen(p_duration.microseconds)) {
        return p_duration.microseconds * 1000000;
      }
      else if (ischosen(p_duration.milliseconds)) {
        return p_duration.milliseconds * 1000;
      }
      else if (ischosen(p_duration.seconds)) {
        return p_duration.seconds;
      }
      else if (ischosen(p_duration.minutes)) {
        return p_duration.minutes * 60;
      }
      else if (ischosen(p_duration.hours)) {
        return p_duration.hours * 3600;
      }
      else if (ischosen(p_duration.sixtyHours)) {
        return p_duration.sixtyHours * 60 * 3600;
      }
      else if (ischosen(p_duration.sixtyHours)) {
        return p_duration.sixtyHours * 60 * 3600;
      }
      // No choice!
      return p_duration.years * 31536000; // One calendar common year has 365 days
    }

  } // End of group dc

  group ctl {

    function f_build_ctl(
                         in charstring p_ea_certificate_id,
                         in charstring p_aa_certificate_id,
                         in charstring p_rca_certificate_id,
                         out ToBeSignedRcaCtl p_to_be_signed_rca_ctl
                         ) {
      // Local variables
      var EtsiTs103097Certificate v_ea_certificate;
      var EtsiTs103097Certificate v_aa_certificate;
      var Oct32 v_rca_hash;
      var CtlCommands v_ctl_commands;
      var Time32 v_time;

      log(">>> f_build_ctl");

      // Load certificates
      f_readCertificate(p_ea_certificate_id, v_ea_certificate);
      f_readCertificate(p_aa_certificate_id, v_aa_certificate);
      f_getCertificateHash256(p_rca_certificate_id, v_rca_hash);
      v_ctl_commands := {
        { add := { ea := valueof(m_ea_entry(v_ea_certificate, PICS_EA_ENDPOINT)) } },
        { add := { aa := valueof(m_aa_entry(v_aa_certificate, PICS_AA_ENDPOINT)) } },
        { add := { dc := valueof(m_dc_entry(PICS_DC_ENDPOINT, { f_hashedId8FromSha256(v_rca_hash) })) } }
      };
      log("f_build_ctl: v_ctl_commands= ", v_ctl_commands);
      // Build the main data structure
      v_time := f_getCurrentTime() / 1000;/*in seconds*/
      p_to_be_signed_rca_ctl := valueof(m_to_be_signed_rca_full_ctl(v_time + 30 * 86400/*30 days in seconds*/, PX_CTL_SEQUENCE_NUMBER, v_ctl_commands));

      log("<<< f_build_ctl: p_to_be_signed_rca_ctl= ", p_to_be_signed_rca_ctl);
    } // End of function f_build_ctl

    function f_sign_dc_ctl(
                           in charstring p_signer_certificate_id,
                           in ToBeSignedRcaCtl p_to_be_signed_rca_ctl,
                           out Ieee1609Dot2Data p_ieee_1609Dot2_signed_data
                           ) {
      // Local variables
      var EtsiTs103097Certificate v_certificate;
      var EtsiTs102941Data v_etsi_ts_102941_data;
      var octetstring v_pki_message;
      var ToBeSignedData v_tbs;
      var octetstring v_private_key;
      var octetstring v_issuer;
      var bitstring v_tbs_encoded;
      var octetstring v_sig;
      var Signature v_signature;

      log(">>> f_sign_dc_ctl");

      f_readSigningKey(p_signer_certificate_id, v_private_key);
      f_getCertificateHash(p_signer_certificate_id, v_issuer);
      f_readCertificate(p_signer_certificate_id, v_certificate);

      // Encode the main data structure
      v_etsi_ts_102941_data := valueof(m_etsiTs102941Data_to_be_signed_rca_ctl(p_to_be_signed_rca_ctl));
      v_pki_message := bit2oct(encvalue(v_etsi_ts_102941_data));
      // Signed the encoded PKI message
      v_tbs := valueof(
                       m_toBeSignedData(
                                        m_signedDataPayload(
                                                            m_etsiTs103097Data_unsecured(v_pki_message)
                                                            ),
                                        m_headerInfo_inner_pki_ctl_response(-, (f_getCurrentTime() * 1000)/*us*/)
                                        )
                       );
      v_tbs_encoded := encvalue(v_tbs);
      // Sign the certificate
      v_sig := f_signWithEcdsa(bit2oct(v_tbs_encoded), v_issuer, v_private_key);
      if ((PX_VE_ALG == e_nist_p256) or (PX_VE_ALG == e_brainpool_p256_r1)) {
        v_signature := valueof(
                               m_signature_ecdsaNistP256(
                                                         m_ecdsaP256Signature(
                                                                              m_eccP256CurvePoint_x_only(
                                                                                                         substr(v_sig, 0, 32)
                                                                                                         ),
                                                                              substr(v_sig, 32, 32)
                                                                              )
                                                         ));
        p_ieee_1609Dot2_signed_data := valueof(
                                               m_etsiTs103097Data_signed(
                                                                         m_signedData(
                                                                                      sha256,
                                                                                      v_tbs,
                                                                                      m_signerIdentifier_certificates({v_certificate}),
                                                                                      v_signature
                                                                                      )
                                                                         )
                                               );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        v_signature := valueof(
                               m_signature_ecdsaBrainpoolP384r1(
                                                                m_ecdsaP384Signature(
                                                                                     m_eccP384CurvePoint_x_only(
                                                                                                                substr(v_sig, 0, 48)
                                                                                                                ),
                                                                                     substr(v_sig, 48, 48)
                                                                                     )
                                                                ));
        p_ieee_1609Dot2_signed_data := valueof(
                                               m_etsiTs103097Data_signed(
                                                                         m_signedData(
                                                                                      sha384,
                                                                                      v_tbs,
                                                                                      m_signerIdentifier_certificates({v_certificate}),
                                                                                      v_signature
                                                                                      )
                                                                         )
                                               );
      }
      log("<<< f_sign_dc_ctl: p_ieee_1609Dot2_signed_data= ", p_ieee_1609Dot2_signed_data);
    } // End of function f_sign_dc_ctl

    function f_verify_full_ctl(
                               in ToBeSignedRcaCtl p_to_be_signed_rca_ctl
                               ) return boolean {
      log(">>> f_verify_full_ctl: p_to_be_signed_rca_ctl= ", p_to_be_signed_rca_ctl);

      // 1. Check mandatory fields
      log("f_verify_full_ctl matching= ", match(p_to_be_signed_rca_ctl, mw_to_be_signed_rca_full_ctl));
      if (match(p_to_be_signed_rca_ctl, mw_to_be_signed_rca_full_ctl) == false) {
        return false;
      }

      log("f_verify_full_ctl: ctlCommands length: ", lengthof(p_to_be_signed_rca_ctl.ctlCommands));
      for (var integer v_i := 0;  v_i < lengthof(p_to_be_signed_rca_ctl.ctlCommands); v_i := v_i + 1) {
        var CtlCommand v_ctl_command := p_to_be_signed_rca_ctl.ctlCommands[v_i];

        if (ischosen(v_ctl_command.delete)) {
          log("f_verify_full_ctl: ctlCommands shall not contains 'delete' variant");
          return false;
        } else {
          if (f_verify_ctl_entry(v_ctl_command.add) == false) {
            log("f_verify_full_ctl: ctlCommands contains invalid entries");
            return false;
          }
        }
      } // End of 'for' statements
      
      return true;
    } // End of function f_verify_full_ctl

    function f_verify_ctl_entry(
                                in CtlEntry p_ctl_entry
                                ) return boolean {
      log(">>> f_verify_ctl_entry: p_ctl_entry=", p_ctl_entry);

      if (ischosen(p_ctl_entry.rca)) {
        if (match(p_ctl_entry.rca, mw_root_ca_entry(mw_etsiTs103097Certificate)) == false) {
          return false;
        } else {
          // TODO Verify RCA certificate & signature
        }
     } else if (ischosen(p_ctl_entry.ea)) {
        if (match(p_ctl_entry.ea, mw_ea_entry(mw_etsiTs103097Certificate)) == false) {
          return false;
        } else {
          // TODO Verify RCA certificate & signature
        }
      } else if (ischosen(p_ctl_entry.aa)) {
        if (match(p_ctl_entry.aa, mw_aa_entry(mw_etsiTs103097Certificate)) == false) {
          return false;
        } else {
          // TODO Verify RCA certificate & signature
        }
      } else if (ischosen(p_ctl_entry.dc)) {
        if (match(p_ctl_entry.dc, mw_dc_entry) == false) {
          return false;
        } else {
          // TODO Verify RCA certificate & signature
        }
      } else {
        return false;
      }

      return true;
    } // End of function f_verify_ctl_entry

  } // End of group ctl

  group crl {

    function f_build_crl(
                         in template (omit) charstring p_ea_certificate_id := omit,
                         in template (omit) charstring p_aa_certificate_id := omit,
                         out ToBeSignedCrl p_to_be_signed_crl
                         ) {
      // Local variables
      var HashedId8 v_hashed_id8;
      var CrlEntries v_crl_entries := {}; // Empty list
      var integer v_counter := 0;
      var Time32 v_time;

      log(">>> f_build_crl");

      if (ispresent(p_ea_certificate_id)) {
        f_getCertificateHash(valueof(p_ea_certificate_id), v_hashed_id8);
        v_crl_entries[v_counter] := v_hashed_id8;
        v_counter := v_counter + 1;
      }
      if (ispresent(p_aa_certificate_id)) {
        f_getCertificateHash(valueof(p_aa_certificate_id), v_hashed_id8);
        v_crl_entries[v_counter] := v_hashed_id8;
        v_counter := v_counter + 1;
      }
      log("f_build_crl: v_crl_entries= ", v_crl_entries);
      // Build the main data structure
      v_time := f_getCurrentTime() / 1000; /*in seconds*/
      p_to_be_signed_crl := valueof(m_to_be_signed_crl(v_time, v_time + 30 * 86400/*30 days in seconds*/, v_crl_entries));

      log("<<< f_build_crl: p_to_be_signed_crl= ", p_to_be_signed_crl);
    } // End of function f_build_crl

    function f_sign_dc_crl(
                           in charstring p_signer_certificate_id,
                           in ToBeSignedCrl p_to_be_signed_crl,
                           out Ieee1609Dot2Data p_ieee_1609Dot2_signed_data
                           ) {
      // Local variables
      var EtsiTs103097Certificate v_certificate;
      var EtsiTs102941Data v_etsi_ts_102941_data;
      var octetstring v_pki_message;
      var ToBeSignedData v_tbs;
      var octetstring v_private_key;
      var octetstring v_issuer;
      var bitstring v_tbs_encoded;
      var octetstring v_sig;
      var Signature v_signature;

      log(">>> f_sign_dc_crl");

      f_readSigningKey(p_signer_certificate_id, v_private_key);
      f_getCertificateHash(p_signer_certificate_id, v_issuer);
      f_readCertificate(p_signer_certificate_id, v_certificate);

      // Encode the main data structure
      v_etsi_ts_102941_data := valueof(m_etsiTs102941Data_to_be_signed_crl(p_to_be_signed_crl));
      v_pki_message := bit2oct(encvalue(v_etsi_ts_102941_data));
      // Signed the encoded PKI message
      v_tbs := valueof(
                       m_toBeSignedData(
                                        m_signedDataPayload(
                                                            m_etsiTs103097Data_unsecured(v_pki_message)
                                                            ),
                                        m_headerInfo_inner_pki_crl_response(-, (f_getCurrentTime() * 1000)/*us*/)
                                        )
                       );
      v_tbs_encoded := encvalue(v_tbs);
      // Sign the certificate
      v_sig := f_signWithEcdsa(bit2oct(v_tbs_encoded), v_issuer, v_private_key);
      if ((PX_VE_ALG == e_nist_p256) or (PX_VE_ALG == e_brainpool_p256_r1)) {
        v_signature := valueof(
                               m_signature_ecdsaNistP256(
                                                         m_ecdsaP256Signature(
                                                                              m_eccP256CurvePoint_x_only(
                                                                                                         substr(v_sig, 0, 32)
                                                                                                         ),
                                                                              substr(v_sig, 32, 32)
                                                                              )
                                                         ));
        p_ieee_1609Dot2_signed_data := valueof(
                                               m_etsiTs103097Data_signed(
                                                                         m_signedData(
                                                                                      sha256,
                                                                                      v_tbs,
                                                                                      m_signerIdentifier_certificates({v_certificate}),
                                                                                      v_signature
                                                                                      )
                                                                         )
                                               );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
        v_signature := valueof(
                               m_signature_ecdsaBrainpoolP384r1(
                                                                m_ecdsaP384Signature(
                                                                                     m_eccP384CurvePoint_x_only(
                                                                                                                substr(v_sig, 0, 48)
                                                                                                                ),
                                                                                     substr(v_sig, 48, 48)
                                                                                     )
                                                                ));
        p_ieee_1609Dot2_signed_data := valueof(
                                               m_etsiTs103097Data_signed(
                                                                         m_signedData(
                                                                                      sha384,
                                                                                      v_tbs,
                                                                                      m_signerIdentifier_certificates({v_certificate}),
                                                                                      v_signature
                                                                                      )
                                                                         )
                                               );
      }
      log("<<< f_sign_dc_crl: p_ieee_1609Dot2_signed_data= ", p_ieee_1609Dot2_signed_data);
    } // End of function f_sign_dc_crl
    function f_verify_full_crl(
                               in ToBeSignedCrl p_to_be_signed_crl
                               ) return boolean {
      log(">>> f_verify_full_crl: p_to_be_signed_crl= ", p_to_be_signed_crl);
      // 1. Check mandatory fields
      log("f_verify_full_crl matching= ", match(p_to_be_signed_crl, mw_to_be_signed_crl));
      if (match(p_to_be_signed_crl, mw_to_be_signed_crl) == false) {
        return false;
      log("f_verify_full_crl: entries length: ", lengthof(p_to_be_signed_crl.entries));
      for (var integer v_i := 0;  v_i < lengthof(p_to_be_signed_crl.entries); v_i := v_i + 1) {
        var CrlEntry v_crl_entry := p_to_be_signed_crl.entries[v_i];
        log("f_verify_full_crl: crlEntry: v_crl_entry");
      } // End of 'for' statements
      
      return true;
    } // End of function f_verify_full_crl

  } // End of group crl

  group tlm {

    function f_build_tlm(
                         in charstring p_tlm_certificate_id,
                         in charstring p_rca_certificate_id,
                         out ToBeSignedTlmCtl p_to_be_signed_tlm_crl
                         ) {
      // Local variables
      var EtsiTs103097Certificate v_tlm_certificate;
      var EtsiTs103097Certificate v_rca_certificate;
      var CtlCommands v_ctl_commands; // Empty list
      var Oct32 v_rca_hash;
      var Time32 v_time;

      log(">>> f_build_tlm");

      // Load certificates
      f_readCertificate(p_tlm_certificate_id, v_tlm_certificate);
      f_readCertificate(p_rca_certificate_id, v_rca_certificate);
      f_getCertificateHash256(p_rca_certificate_id, v_rca_hash);
      // Create ctlCommnand list
      v_ctl_commands := {
        { add := { tlm := valueof(m_tlm_entry(v_tlm_certificate, PICS_TLM_ENDPOINT)) } },
        { add := { rca := valueof(m_root_ca_entry(v_rca_certificate)) } },
        { add := { dc := valueof(m_dc_entry(PICS_DC_ENDPOINT, { f_hashedId8FromSha256(v_rca_hash) })) } }
      };
      log("f_build_tlm: v_ctl_commands= ", v_ctl_commands);
      // Build the main data structure
      v_time := f_getCurrentTimeUtc() / 1000/*in s*/;
      //log("f_build_ctl: v_time= ", v_time);
      //log("f_build_ctl: v_time + 86400= ", v_time + 86400);
      p_to_be_signed_tlm_crl := valueof(mw_to_be_signed_tlm_full_ctl(v_time + 86400/*1days*/, 7, v_ctl_commands));

      log("<<< f_build_tlm: p_to_be_signed_tlm_crl= ", p_to_be_signed_tlm_crl);
    } // End of function f_buif_build_tlmld_Tlm

    function f_verify_full_ectl(
                               in ToBeSignedRcaCtl p_to_be_signed_tlm_ectl
                               ) return boolean {
      log(">>> f_verify_full_ectl: p_to_be_signed_tlm_ectl= ", p_to_be_signed_tlm_ectl);

      // 1. Check mandatory fields
      log("f_verify_full_ectl matching= ", match(p_to_be_signed_tlm_ectl, mw_to_be_signed_rca_full_ctl));
      if (match(p_to_be_signed_tlm_ectl, mw_to_be_signed_rca_full_ctl) == false) {
        return false;
      }

      log("f_verify_full_ectl: ctlCommands length: ", lengthof(p_to_be_signed_tlm_ectl.ctlCommands));
      for (var integer v_i := 0;  v_i < lengthof(p_to_be_signed_tlm_ectl.ctlCommands); v_i := v_i + 1) {
        var CtlCommand v_ectl_command := p_to_be_signed_tlm_ectl.ctlCommands[v_i];

        if (ischosen(v_ectl_command.delete)) {
          log("f_verify_full_ectl: ctlCommands shall not contains 'delete' variant");
        } else {
          if (f_verify_ectl_entry(v_ectl_command.add) == false) {
            log("f_verify_full_ectl: ctlCommands contains invalid entries");
        }
      } // End of 'for' statements
    function f_verify_ectl_entry(
                                 in CtlEntry p_ctl_entry
                                 ) return boolean {
      log(">>> f_verify_ectl_entry: p_ctl_entry=", p_ctl_entry);

      if (ischosen(p_ctl_entry.tlm)) {
        if (match(p_ctl_entry.tlm, mw_tlm_entry(mw_etsiTs103097Certificate)) == false) {
        } else {
          // TODO Verify RCA certificate & signature
      } else if (ischosen(p_ctl_entry.dc)) {
        if (match(p_ctl_entry.dc, mw_dc_entry) == false) {
        } else {
          // TODO Verify RCA certificate & signature
      } else if (ischosen(p_ctl_entry.rca)) {
        if (match(p_ctl_entry.rca, mw_root_ca_entry(mw_etsiTs103097Certificate)) == false) {
        } else {
          // TODO Verify RCA certificate & signature
      } else {
        return false;
      return true;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    function f_verify_tlm_ectl_response_message(
                                                in EtsiTs103097Data p_etsi_ts_103097_signed_data,
                                                in boolean p_check_security := true,
                                                out ToBeSignedTlmCtl p_to_be_signed_tlm_ectl
                                                ) return boolean {
      var bitstring v_etsi_ts_102941_data_msg;
      var bitstring v_tbs;
      var Certificate v_certificate;
      var boolean v_result;
      var EtsiTs102941Data v_etsi_ts_102941_data;

      log(">>> f_verify_tlm_ectl_response_message: p_etsi_ts_103097_signed_data= ", p_etsi_ts_103097_signed_data);

      // 1. Verify signature
      log("f_verify_tlm_ectl_response_message: p_etsi_ts_103097_signed_data.content.signedData.tbsData= ", p_etsi_ts_103097_signed_data.content.signedData.tbsData);
      v_tbs := encvalue(p_etsi_ts_103097_signed_data.content.signedData.tbsData);
      if (ischosen(p_etsi_ts_103097_signed_data.content.signedData.signer.certificate)) {
          v_certificate := p_etsi_ts_103097_signed_data.content.signedData.signer.certificate[0];
      } else {
          var charstring v_certificate_id;
          if (f_getCertificateFromDigest(p_etsi_ts_103097_signed_data.content.signedData.signer.digest, v_certificate, v_certificate_id) == false) {
            log("f_verify_tlm_ectl_response_message: Failed to retrieve certificate from digest ", p_etsi_ts_103097_signed_data.content.signedData.signer.digest);
            if (p_check_security == true) {
              return false;
            }
          }
      }
      if (ischosen(p_etsi_ts_103097_signed_data.content.signedData.signature_.ecdsaBrainpoolP384r1Signature)) {
        v_result := f_verifyEcdsa(bit2oct(v_tbs), int2oct(0, 48), p_etsi_ts_103097_signed_data.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey);
      } else {
        v_result := f_verifyEcdsa(bit2oct(v_tbs), int2oct(0, 32), p_etsi_ts_103097_signed_data.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey);
      }
      if (v_result == false) {
        log("f_verify_tlm_ectl_response_message: Failed to verify signature");
        if (p_check_security == true) {
          return false;
        }
      }
      v_etsi_ts_102941_data_msg := oct2bit(p_etsi_ts_103097_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData);
      if (decvalue(v_etsi_ts_102941_data_msg, v_etsi_ts_102941_data) != 0) {
        log("f_verify_tlm_ectl_response_message: Failed to decode EtsiTs102941Data");
        return false;
      } else {
        log("f_verify_tlm_ectl_response_message: v_etsi_ts_102941_data= ", v_etsi_ts_102941_data);
        log("f_verify_pki_response_message: TlmCertificateTrustListMessage matching= ", match(v_etsi_ts_102941_data, mw_etsiTs102941Data_to_be_signed_tlm_ctl));
        if (match(v_etsi_ts_102941_data, mw_etsiTs102941Data_to_be_signed_tlm_ctl) == false) {
          log("f_verify_tlm_ectl_response_message: Failed to decode certificateTrustListTlm");
          return false;
        } else {
          var Time32 v_time := (f_getCurrentTime()/* - 1072915200000*/) / 1000;
          p_to_be_signed_tlm_ectl := v_etsi_ts_102941_data.content.certificateTrustListTlm;
          log("f_verify_tlm_ectl_response_message: p_to_be_signed_tlm_ectl= ", p_to_be_signed_tlm_ectl);
          if (p_to_be_signed_tlm_ectl.nextUpdate <= v_time) {
            log("f_verify_tlm_ectl_response_message: Invalid nextUpdate value: compared values=", p_to_be_signed_tlm_ectl.nextUpdate, "/", v_time);
            return false;
          }
          // TODO Verify RCA certificate & signature
        }
      }

      return true;
    }

    function f_verify_broadcasted_delta_ctl(
                                            in GeoNetworkingPdu p_geonetworking_pdu,
                                            in boolean p_check_security := true
                                            ) return boolean {

      var EtsiTs103097Data v_secured_msg;
      var bitstring v_etsi_ts_102941_data_msg;
      var bitstring v_tbs;
      var Certificate v_certificate;
      var boolean v_result;
      var EtsiTs102941Data v_etsi_ts_102941_data;

      log(">>> f_verify_broadcasted_delta_ctl: p_geonetworking_pdu= ", p_geonetworking_pdu);

      if (not(ispresent(p_geonetworking_pdu.gnPacket.securedMsg))) {
        return false;
      }

      v_secured_msg := p_geonetworking_pdu.gnPacket.securedMsg;
      // 1. Verify signature
      log("f_verify_broadcasted_delta_ctl: v_secured_msg= ", v_secured_msg);
      v_tbs := encvalue(v_secured_msg.content.signedData.tbsData);
      if (ischosen(v_secured_msg.content.signedData.signer.certificate)) {
          v_certificate := v_secured_msg.content.signedData.signer.certificate[0];
      } else {
          var charstring v_certificate_id;
          if (f_getCertificateFromDigest(v_secured_msg.content.signedData.signer.digest, v_certificate, v_certificate_id) == false) {
            log("f_verify_broadcasted_delta_ctl: Failed to retrieve certificate from digest ", v_secured_msg.content.signedData.signer.digest);
            if (p_check_security == true) {
              return false;
            }
          }
      }
      if (ischosen(v_secured_msg.content.signedData.signature_.ecdsaBrainpoolP384r1Signature)) {
        v_result := f_verifyEcdsa(bit2oct(v_tbs), int2oct(0, 48), v_secured_msg.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey);
      } else {
        v_result := f_verifyEcdsa(bit2oct(v_tbs), int2oct(0, 32), v_secured_msg.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey);
      }
      if (v_result == false) {
        log("f_verify_broadcasted_delta_ctl: Failed to verify signature");
        if (p_check_security == true) {
          return false;
        }
      }
      v_etsi_ts_102941_data_msg := oct2bit(v_secured_msg.content.signedData.tbsData.payload.data.content.unsecuredData);
      if (decvalue(v_etsi_ts_102941_data_msg, v_etsi_ts_102941_data) != 0) {
        log("f_verify_broadcasted_delta_ctl: Failed to decode EtsiTs102941Data");
        return false;
      } else {
        log("f_verify_broadcasted_delta_ctl: v_etsi_ts_102941_data= ", v_etsi_ts_102941_data);
        // TODO
      }
      
      return true;
    } // End of function f_verify_broadcasted_delta_ctl

    function f_verify_and_extract_payload(
                                            in GeoNetworkingPdu p_geonetworking_pdu,
                                            in boolean p_check_security := true,
                                            out octetstring p_payload
                                            ) return boolean {

      var EtsiTs103097Data v_secured_msg;
      var bitstring v_tbs;
      var Certificate v_certificate;
      var boolean v_result;
      var EtsiTs102941Data v_etsi_ts_102941_data;

      log(">>> f_verify_and_extract_payload: p_geonetworking_pdu= ", p_geonetworking_pdu);

      if (not(ispresent(p_geonetworking_pdu.gnPacket.securedMsg))) {
        return false;
      }

      v_secured_msg := p_geonetworking_pdu.gnPacket.securedMsg;
      // 1. Verify signature
      log("f_verify_and_extract_payload: v_secured_msg= ", v_secured_msg);
      v_tbs := encvalue(v_secured_msg.content.signedData.tbsData);
      if (ischosen(v_secured_msg.content.signedData.signer.certificate)) {
          v_certificate := v_secured_msg.content.signedData.signer.certificate[0];
      } else {
          var charstring v_certificate_id;
          if (f_getCertificateFromDigest(v_secured_msg.content.signedData.signer.digest, v_certificate, v_certificate_id) == false) {
            log("f_verify_and_extract_payload: Failed to retrieve certificate from digest ", v_secured_msg.content.signedData.signer.digest);
            if (p_check_security == true) {
              return false;
            }
          }
      }
      if (ischosen(v_secured_msg.content.signedData.signature_.ecdsaBrainpoolP384r1Signature)) {
        v_result := f_verifyEcdsa(bit2oct(v_tbs), int2oct(0, 48), v_secured_msg.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey);
      } else {
        v_result := f_verifyEcdsa(bit2oct(v_tbs), int2oct(0, 32), v_secured_msg.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey);
      }
      if (v_result == false) {
        log("f_verify_and_extract_payload: Failed to verify signature");
        if (p_check_security == true) {
          return false;
        }
      }
      log("f_verify_and_extract_payload: v_etsi_ts_102941_data= ", v_secured_msg.content.signedData.tbsData.payload.data.content.unsecuredData);
      // TODO 
      
      return true;
    } // End of function f_verify_and_extract_payload

ASN.1 Documenter's avatar
ASN.1 Documenter committed
  } // End of group tlm

  group awaiting_messages {

    function f_await_http_inner_ec_request_response(
                                                    out Oct32 p_private_key,
                                                    out Oct32 p_compressed_public_key,
                                                    out integer p_compressed_mode,
                                                    out InnerEcResponse p_inner_ec_response,
                                                    in boolean p_strict_checks := true
                                                    ) runs on ItsPkiHttp return boolean {
      var Headers v_headers;
      var Oct32 v_request_hash;
      var Oct16 v_encrypted_sym_key;
      var Oct16 v_aes_sym_key;
      var HashedId8 v_aes_sym_key_hashed_id8;
      var Oct16 v_authentication_vector;
      var Oct12 v_nonce;
      var octetstring v_salt;
      var Ieee1609Dot2Data v_ieee1609dot2_signed_and_encrypted_data;
      var EtsiTs102941Data v_etsi_ts_102941_data;
      var HttpMessage v_response;

      log(">>> f_await_http_inner_ec_request_response: p_strict_checks=", p_strict_checks);
      
      f_http_build_inner_ec_request(p_private_key, p_compressed_public_key, p_compressed_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce, v_salt, v_ieee1609dot2_signed_and_encrypted_data, v_request_hash);
      v_aes_sym_key_hashed_id8 := f_hashedId8FromSha256(f_hashWithSha256('80'O & v_aes_sym_key)); // Used to macth the response
      f_init_default_headers_list(-, "inner_ec_request", v_headers);
      f_http_send(
                  v_headers, 
                  m_http_request(
                                 m_http_request_post(
                                                     PICS_HTTP_POST_URI_EC,
                                                     v_headers,
                                                     m_http_message_body_binary(
                                                                                m_binary_body_ieee1609dot2_data(
                                                                                                                v_ieee1609dot2_signed_and_encrypted_data
                                                                                                                )))));
      tc_ac.start;
      alt {
        [] a_await_ec_http_request_from_iut(
                                            mw_http_response(
                                                             mw_http_response_ok(
                                                                                 mw_http_message_body_binary(
                                                                                                             mw_binary_body_ieee1609dot2_data(
                                                                                                                                              mw_enrolmentResponseMessage(
                                                                                                                                                                          mw_encryptedData(
                                                                                                                                                                                           { *, mw_recipientInfo_pskRecipInfo(v_aes_sym_key_hashed_id8), * },
                                                                                                                                                                                           mw_symmetricCiphertext_aes128ccm
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                                                                           )))))),
                                            v_response
                                            ) {
          tc_ac.stop;
          
          if (f_verify_pki_response_message(p_private_key, v_aes_sym_key, v_authentication_vector, vc_eaWholeHash, v_response.response.body.binary_body.ieee1609dot2_data, p_strict_checks, -, v_etsi_ts_102941_data) == false) {
            log("f_await_http_inner_ec_request_response: Failed to verify PKI message ***");
            if (p_strict_checks) {
              return false;
            }
          }
          log("f_await_http_inner_ec_request_response: Receive ", v_etsi_ts_102941_data, " ***");
          // Verify the received EC certificate
          log("f_await_http_inner_ec_request_response: match ", match(v_etsi_ts_102941_data.content, mw_enrolmentResponse(mw_innerEcResponse_ok(substr(v_request_hash, 0, 16), mw_etsiTs103097Certificate(-, mw_toBeSignedCertificate_ec)))), " ***"); // TODO In TITAN, this is the only way to get the unmatching in log
          if (match(v_etsi_ts_102941_data.content, mw_enrolmentResponse(mw_innerEcResponse_ok(?/*FIXME YANN Blackberry substr(v_request_hash, 0, 16)*/, mw_etsiTs103097Certificate(-, mw_toBeSignedCertificate_ec)))) == false) {
            log("f_await_http_inner_ec_request_response: Unexpected message received ***");
            if (p_strict_checks) {
              return false;
            }
          }
          if (ischosen(v_etsi_ts_102941_data.content.enrolmentResponse) and ispresent(v_etsi_ts_102941_data.content.enrolmentResponse.certificate)) {
            var HashedId8 v_ec_cert_hashed_id8;
              
            if (f_verify_ec_certificate(v_etsi_ts_102941_data.content.enrolmentResponse.certificate, vc_eaCertificate, vc_eaHashedId8, p_compressed_public_key, p_compressed_mode, v_ec_cert_hashed_id8) == false) {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
              log("f_await_http_inner_ec_request_response: Cannot verify EC certificate signature ***");
              if (p_strict_checks) {
                return false;
              }
            }
            p_inner_ec_response := v_etsi_ts_102941_data.content.enrolmentResponse;
            log("f_await_http_inner_ec_request_response: Well-secured EA certificate received ***");
            log("p_inner_ec_response= ", p_inner_ec_response);
          } else {
            log("f_await_http_inner_ec_request_response: Invalid message received ***");
            return false;
          }
        }
        [] tc_ac.timeout {
          log("f_await_http_inner_ec_request_response: Expected message not received ***");
        }
      } // End of 'alt' statement
      
      return true;
    } // End of function f_await_http_inner_ec_request_response
    
    function f_await_ec_request_send_response(
                                              out InnerEcResponse p_inner_ec_response,
                                              out HttpMessage p_request
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                              ) runs on ItsPkiHttp return boolean {
      var boolean v_result := false;
      
      log(">>> f_await_ec_request_send_response");
      
      tc_ac.start;
      alt {
        [] a_await_ec_http_request_from_iut(
                                            mw_http_request(
                                                            mw_http_request_post(
                                                                                 PICS_HTTP_POST_URI_EC,
                                                                                 -,
                                                                                 mw_http_message_body_binary(
                                                                                                             mw_binary_body_ieee1609dot2_data(
                                                                                                                                              mw_enrolmentRequestMessage(
                                                                                                                                                                         mw_encryptedData(
                                                                                                                                                                                          -,
                                                                                                                                                                                          mw_symmetricCiphertext_aes128ccm
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                                                                          )))))),
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                            ) {
          var Ieee1609Dot2Data v_ieee1609dot2_signed_and_encrypted_data;
          var EtsiTs102941Data v_etsi_ts_102941_data;
          var Oct16 v_request_hash;
          var Oct16 v_aes_enc_key;
          var InnerEcRequest v_inner_ec_request;
          var template (value) HttpMessage v_response;
          var Headers v_headers;
          var EtsiTs103097Certificate v_ec_certificate;
          var HashedId8 v_ec_certificate_hashed_id8;
ASN.1 Documenter's avatar
ASN.1 Documenter committed
          
          tc_ac.stop;
          
          f_init_default_headers_list(-, "inner_ec_response", v_headers);
          
          if (f_verify_pki_request_message(vc_eaPrivateEncKey, vc_eaWholeHash/*salt*/, ''O, p_request.request.body.binary_body.ieee1609dot2_data, false, v_request_hash, v_etsi_ts_102941_data, v_aes_enc_key) == false) { // Cannot decrypt the message
ASN.1 Documenter's avatar
ASN.1 Documenter committed
            log("f_await_ec_request_send_response: Failed to verify PKI message ***");
            // Send error message
            v_response := m_http_response(m_http_response_ko(m_http_message_body_binary(m_binary_body_ieee1609dot2_data(v_ieee1609dot2_signed_and_encrypted_data)), v_headers, 400, "Bad request")); // Initialize v_reponse with an error message
          } else {
            log("f_await_ec_request_send_response: Receive ", v_etsi_ts_102941_data, " ***");
            if (f_verify_inner_ec_request_signed_for_pop(v_etsi_ts_102941_data, v_inner_ec_request) == false) {
              log("f_await_ec_request_send_response: Failed to verify PKI message ***");
              // Send error message
              f_http_build_inner_ec_response(v_inner_ec_request/*Not required*/, cantparse, v_request_hash, -, -, v_aes_enc_key, v_ec_certificate, v_ec_certificate_hashed_id8, p_inner_ec_response, v_ieee1609dot2_signed_and_encrypted_data);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
              v_response := m_http_response(m_http_response_ok(m_http_message_body_binary(m_binary_body_ieee1609dot2_data(v_ieee1609dot2_signed_and_encrypted_data)), v_headers));
            } else {
              f_http_build_inner_ec_response(v_inner_ec_request, ok, v_request_hash, vc_eaPrivateKey, vc_eaWholeHash, v_aes_enc_key, v_ec_certificate, v_ec_certificate_hashed_id8, p_inner_ec_response, v_ieee1609dot2_signed_and_encrypted_data);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
              v_response := m_http_response(m_http_response_ok(m_http_message_body_binary(m_binary_body_ieee1609dot2_data(v_ieee1609dot2_signed_and_encrypted_data)), v_headers));
              v_result := true;
            }
            f_http_send(v_headers, v_response);
          }
        }
        [] tc_ac.timeout {
          log("f_await_ec_request_send_response: Expected message not received ***");
        }
      } // End of 'alt' statement
      
      return v_result;
    } // End of function f_await_ec_request_send_response
    
    function f_await_ec_request_send_error_response(
                                                    out HttpMessage p_request
                                                    ) runs on ItsPkiHttp {
      var Ieee1609Dot2Data v_ieee1609dot2_signed_and_encrypted_data;
      var boolean v_result := false;
      
      log(">>> f_await_ec_request_send_error_response");
      
      tc_ac.start;
      alt {
        [] a_await_ec_http_request_from_iut(
                                            mw_http_request(
                                                            mw_http_request_post(
                                                                                 PICS_HTTP_POST_URI_EC,
                                                                                 -,
                                                                                 mw_http_message_body_binary(
                                                                                                             mw_binary_body_ieee1609dot2_data(
                                                                                                                                              mw_enrolmentRequestMessage(
                                                                                                                                                                         mw_encryptedData(
                                                                                                                                                                                          -,
                                                                                                                                                                                          mw_symmetricCiphertext_aes128ccm
                                                                                                                                                                                          )))))),
                                            p_request
                                            ) {
          var template (value) HttpMessage v_response;
          var Headers v_headers;
          
          tc_ac.stop;
          
          f_init_default_headers_list(-, "inner_ec_response", v_headers);
          log("f_await_ec_request_send_error_response: Failed to verify PKI message ***");
          // Send error message
          v_response := m_http_response(m_http_response_ko(m_http_message_body_binary(m_binary_body_ieee1609dot2_data(v_ieee1609dot2_signed_and_encrypted_data)), v_headers, 400, "Bad request")); // Initialize v_reponse with an error message
          f_http_send(v_headers, v_response);
        }
        [] tc_ac.timeout {
          log("f_await_ec_request_send_error_response: Expected message not received ***");
        }
      } // End of 'alt' statement

    } // End of function f_await_ec_request_send_error_response
    
ASN.1 Documenter's avatar
ASN.1 Documenter committed
  } // End of group awaiting_messages
  
  group pki_functions {
    
    /**
     * @desc Build a signed and encrypted PKI request message
     * @param p_private_key         Private key for signature
     * @param p_signer_identifier   Signer identifier for signature, could be self or certificate HashedId8
     * @param p_recipientId         Recipient identifier to be inclued in encrypted layer.
     *                              If value is int2oct(0. 8), the recipient id is the HashedId8 of the symmetric key used by the sender to encrypt the message to which the response is built
     * @param p_public_key_compressed The public compressed key (canonical form) for encryption
     * @param p_compressed_mode      The compressed mode of the public compressed key (canonical form) for encryption
     * @param p_pki_message         The PKI message to be secured
     * @param p_ieee1609dot2_signed_and_encrypted_data The secured message
     * @return true on success, false otherwise
     */
    function f_build_pki_secured_request_message_signed_with_pop(
                                                                 in octetstring p_private_key,
                                                                 in SignerIdentifier p_signer_identifier,
                                                                 in HashedId8 p_recipientId,
                                                                 in octetstring p_public_key_compressed,
                                                                 in integer p_compressed_mode,
                                                                 in octetstring p_salt,
                                                                 in octetstring p_pki_message,
                                                                 in SignAlgorithm p_enc_algorithm, // TODO Use RCA to check encryption alg
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                 in boolean p_alter_signature := false,
                                                                 out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                                 out Oct16 p_aes_sym_key,
                                                                 out Oct16 p_encrypted_sym_key,
                                                                 out Oct16 p_authentication_vector,
                                                                 out Oct12 p_nonce,
                                                                 out Oct32 p_request_hash
                                                                 ) return boolean {
      // Local variables
      var template (value) EccP256CurvePoint v_eccP256_curve_point;
      var template (value) ToBeSignedData v_tbs;
      var octetstring v_tbs_signed;
      var Signature v_signature;
      var template (value) Ieee1609Dot2Data v_ieee1609dot2_signed_data;
      var octetstring v_encoded_request;
      var HashedId8 v_recipientId;
      var octetstring v_public_compressed_ephemeral_key;
      var integer v_public_compressed_ephemeral_mode;
      var octetstring v_encrypted_request;
      var EncryptedDataEncryptionKey v_encrypted_data_encryption_key;
      var bitstring v_enc_value;

      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_private_key= ", p_private_key);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_signer_identifier= ", p_signer_identifier);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_recipientId= ", p_recipientId);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_public_key_compressed= ", p_public_key_compressed);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_compressed_mode= ", p_compressed_mode);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_salt= ", p_salt);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_pki_message= ", p_pki_message);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_enc_algorithm= ", p_enc_algorithm);
      log(">>> f_build_pki_secured_request_message_signed_with_pop: p_alter_signature= ", p_alter_signature);
      
      // Signed the encoded PKI message
      v_tbs := m_toBeSignedData(
                                m_signedDataPayload(
                                                    m_etsiTs103097Data_unsecured(p_pki_message)
                                                   ),
                                m_headerInfo_inner_pki_request(-, (f_getCurrentTime() * 1000)/*us*/)
                               );
      log("f_build_pki_secured_request_message_signed_with_pop: v_tbs: ", v_tbs);
      if (ischosen(p_signer_identifier.self_)) {
        v_tbs_signed := f_signWithEcdsa(bit2oct(encvalue(v_tbs)), int2oct(0, 32), p_private_key);
      } else {
        var charstring v_certificate_id;
        var octetstring v_hash;
        // FIXME Huge issue, certificate is BP256 and PX_VE_ALG is e_brainpool_p384_r1, so v_hash & p_private_key are 32 bytes length not 48
        // ==> Need to sign with v_certificate_id capabilities not with PX_VE_ALG :(
        fx_readCertificateFromDigest(p_signer_identifier.digest, v_certificate_id); // TODO Add a wrapper function
        f_getCertificateHash(v_certificate_id, v_hash);
        v_tbs_signed := f_signWithEcdsa(bit2oct(encvalue(v_tbs)), v_hash, p_private_key);
      }
      log("f_build_pki_secured_request_message_signed_with_pop: lengthof(v_tbs_signed)= ", lengthof(v_tbs_signed));
      log("f_build_pki_secured_request_message_signed_with_pop: v_tbs_signed= ", v_tbs_signed);
      if (p_alter_signature == true) {
        v_tbs_signed[0] := '0A'O;
        v_tbs_signed[1] := '0A'O;
        log("f_build_pki_secured_request_message_signed_with_pop: Altered signature= ", v_tbs_signed);
      }
      // Add the signature and create EtsiTs103097Data-Signed data structure
      log("f_build_pki_secured_request_message_signed_with_pop: PX_VE_ALG=", PX_VE_ALG);
      if (PX_VE_ALG == e_nist_p256) {
       v_signature := valueof(
                              m_signature_ecdsaNistP256(
                                                        m_ecdsaP256Signature(
                                                                             m_eccP256CurvePoint_x_only(
                                                                                                        substr(v_tbs_signed, 0, 32)
                                                                                                        ),
                                                                             substr(v_tbs_signed, 32, 32)
                                                                             )
                                                        )
                              );
      } else if (PX_VE_ALG == e_brainpool_p256_r1) {
       v_signature := valueof(
                              m_signature_ecdsaBrainpoolP256r1(
                                                               m_ecdsaP256Signature(
                                                                                    m_eccP256CurvePoint_x_only(
                                                                                                               substr(v_tbs_signed, 0, 32)
                                                                                                               ),
                                                                                    substr(v_tbs_signed, 32, 32)
                                                                                    )
                                                               )
                              );
      } else if (PX_VE_ALG == e_brainpool_p384_r1) {
       v_signature := valueof(
                              m_signature_ecdsaBrainpoolP384r1(
                                                               m_ecdsaP384Signature(
                                                                                    m_eccP384CurvePoint_x_only(
                                                                                                               substr(v_tbs_signed, 0, 48)
                                                                                                               ),
                                                                                    substr(v_tbs_signed, 48, 48)
                                                                                    )
                                                               )
                              );
      }
      log("f_build_pki_secured_request_message_signed_with_pop: v_signature= ", v_signature);
      v_ieee1609dot2_signed_data := m_etsiTs103097Data_signed(
                                                              m_signedData(
                                                                           sha256,
                                                                           v_tbs,
                                                                           p_signer_identifier,
                                                                           v_signature
                                                                           )
                                                              );
      // Encode EtsiTs103097Data-Signed data structure
      v_encoded_request := bit2oct(encvalue(v_ieee1609dot2_signed_data));
      log("f_build_pki_secured_request_message_signed_with_pop: v_encoded_request= ", v_encoded_request);
      // Encrypt encode EtsiTs103097Data-Signed data structure
      if (p_enc_algorithm == e_nist_p256) {
        v_encrypted_request := f_encryptWithEciesNistp256WithSha256(v_encoded_request, p_public_key_compressed, p_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce);
      } else if (p_enc_algorithm == e_brainpool_p256_r1) {
        v_encrypted_request := f_encryptWithEciesBrainpoolp256r1WithSha256(v_encoded_request, p_public_key_compressed, p_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce);
      } else {
        log("f_build_pki_secured_request_message_signed_with_pop: Wrong encryption variant");
        return false;
      }
      log("f_build_pki_secured_request_message_signed_with_pop: p_aes_sym_key= ", p_aes_sym_key);
      log("f_build_pki_secured_request_message_signed_with_pop: p_encrypted_sym_key= ", p_encrypted_sym_key);
      log("f_build_pki_secured_request_message_signed_with_pop: p_authentication_vector= ", p_authentication_vector);
      log("f_build_pki_secured_request_message_signed_with_pop: p_nonce= ", p_nonce);
      log("f_build_pki_secured_request_message_signed_with_pop: p_recipientId= ", p_recipientId);
      if (p_recipientId == int2oct(0, 8)) {
        log("f_build_pki_secured_request_message_signed_with_pop: f_hashWithSha256(v_encrypted_sym_key)= ", f_hashWithSha256(p_encrypted_sym_key));
        v_recipientId := f_hashedId8FromSha256(f_hashWithSha256(p_encrypted_sym_key));
      } else {
        v_recipientId := p_recipientId;
      }
      log("f_build_pki_secured_request_message_signed_with_pop: v_recipientId= ", v_recipientId);
      // Fill Certificate template with the public compressed keys (canonical form)
      if (v_public_compressed_ephemeral_mode == 0) {
        v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_compressed_ephemeral_key));
      } else {
        v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_compressed_ephemeral_key));
      }
      if (p_enc_algorithm == e_nist_p256) {
        v_encrypted_data_encryption_key := valueof(
                                                   m_encryptedDataEncryptionKey_eciesNistP256(
                                                                                              m_evciesP256EncryptedKey(
                                                                                                                       v_eccP256_curve_point,
                                                                                                                       p_encrypted_sym_key, 
                                                                                                                       p_authentication_vector
                                                                                                                       )));
      } else if (p_enc_algorithm == e_brainpool_p256_r1) {
        v_encrypted_data_encryption_key := valueof(
                                                   m_encryptedDataEncryptionKey_eciesBrainpoolP256r1(
                                                                                                     m_evciesP256EncryptedKey(
                                                                                                                              v_eccP256_curve_point,
                                                                                                                              p_encrypted_sym_key, 
                                                                                                                              p_authentication_vector
                                                                                                                              )));
      } else {
        log("f_build_pki_secured_request_message_signed_with_pop: Wrong encryption variant");
        return false;
      }
      
      p_ieee1609dot2_signed_and_encrypted_data := valueof(
                                                          m_etsiTs103097Data_encrypted(
                                                                                       m_encryptedData(
                                                                                                       {
                                                                                                         m_recipientInfo_certRecipInfo(
                                                                                                                                       m_pKRecipientInfo(
                                                                                                                                                         v_recipientId,
                                                                                                                                                         v_encrypted_data_encryption_key
                                                                                                                                                         ))
                                                                                                         },
                                                                                                       m_symmetricCiphertext_aes128ccm(
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                       m_aesCcmCiphertext(
                                                                                                                                                          p_nonce,
                                                                                                                                                          v_encrypted_request
                                                                                                                                                          )
                                                                                                                                       )
                                                                                                       )
                                                                                       )
                                                          );
      
      // The 'p_request_hash' shall be the SHA256 digest of the OER representation of the topmost EtsiTs103097Data-Encoded structure
      v_enc_value := encvalue(p_ieee1609dot2_signed_and_encrypted_data);
      p_request_hash := f_hashWithSha256(bit2oct(v_enc_value));
      log("f_build_pki_secured_request_message_signed_with_pop: p_request_hash= ", p_request_hash);
      
      log("<<< f_build_pki_secured_request_message_signed_with_pop: ", p_pki_message);
      return true;
    } // End of function f_build_pki_secured_request_message_signed_with_pop
    
    /**
     * @desc Build a signed and encrypted PKI request message without POP with signature
     * @param p_recipientId         Recipient identifier to be inclued in encrypted layer.
     *                              If value is int2oct(0. 8), the recipient id is the HashedId8 of the symmetric key used by the sender to encrypt the message to which the response is built
     * @param p_public_key_compressed The public compressed key (canonical form) for encryption
     * @param p_compressed_mode      The compressed mode of the public compressed key (canonical form) for encryption
     * @param p_pki_message         The PKI message to be secured
     * @param p_ieee1609dot2_signed_and_encrypted_data The secured message
     * @return true on success, false otherwise
     */
    function f_build_pki_secured_request_message(
                                                 in HashedId8 p_recipientId,
                                                 in octetstring p_public_key_compressed,
                                                 in integer p_compressed_mode,
                                                 in octetstring p_salt,
                                                 in octetstring p_pki_message,
                                                 in SignAlgorithm p_enc_algorithm,
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                 out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                 out Oct16 p_aes_sym_key,
                                                 out Oct16 p_encrypted_sym_key,
                                                 out Oct16 p_authentication_vector,
                                                 out Oct12 p_nonce,
                                                 out Oct32 p_request_hash
                                                 ) return boolean {
      // Local variables
      var template (value) EccP256CurvePoint v_eccP256_curve_point;
      var HashedId8 v_recipientId;
      var octetstring v_public_compressed_ephemeral_key;
      var integer v_public_compressed_ephemeral_mode;
      var octetstring v_encrypted_request;
      var EncryptedDataEncryptionKey v_encrypted_data_encryption_key;
      var bitstring v_enc_value;
      
      log(">>> f_build_pki_secured_request_message");
      
      // Encrypt encode EtsiTs103097Data-Signed data structure
      if (p_enc_algorithm == e_nist_p256) {
        v_encrypted_request := f_encryptWithEciesNistp256WithSha256(p_pki_message, p_public_key_compressed, p_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce);
      } else if (p_enc_algorithm == e_brainpool_p256_r1) {
        v_encrypted_request := f_encryptWithEciesBrainpoolp256r1WithSha256(p_pki_message, p_public_key_compressed, p_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce);
      } else {
        log("f_build_pki_secured_request_message: Wrong encryption variant");
        return false;
      }
      log("f_build_pki_secured_request_message: p_aes_sym_key= ", p_aes_sym_key);
      log("f_build_pki_secured_request_message: p_encrypted_sym_key= ", p_encrypted_sym_key);
      log("f_build_pki_secured_request_message: p_authentication_vector= ", p_authentication_vector);
      log("f_build_pki_secured_request_message: p_nonce= ", p_nonce);
      log("f_build_pki_secured_request_message: p_recipientId= ", p_recipientId);
      if (p_recipientId == int2oct(0, 8)) {
        log("f_build_pki_secured_request_message: f_hashWithSha256(v_encrypted_sym_key)= ", f_hashWithSha256(p_encrypted_sym_key));
        v_recipientId := f_hashedId8FromSha256(f_hashWithSha256(p_encrypted_sym_key));
      } else {
        v_recipientId := p_recipientId;
      }
      log("f_build_pki_secured_request_message: v_recipientId= ", v_recipientId);
      // Fill Certificate template with the public compressed keys (canonical form)
      if (v_public_compressed_ephemeral_mode == 0) {
        v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_compressed_ephemeral_key));
      } else {
        v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_compressed_ephemeral_key));
      }
      if (p_enc_algorithm == e_nist_p256) {
        v_encrypted_data_encryption_key := valueof(
                                                   m_encryptedDataEncryptionKey_eciesNistP256(
                                                                                              m_evciesP256EncryptedKey(
                                                                                                                       v_eccP256_curve_point,
                                                                                                                       p_encrypted_sym_key, 
                                                                                                                       p_authentication_vector
                                                                                                                       )));
      } else if (p_enc_algorithm == e_brainpool_p256_r1) {
        v_encrypted_data_encryption_key := valueof(
                                                   m_encryptedDataEncryptionKey_eciesBrainpoolP256r1(
                                                                                                     m_evciesP256EncryptedKey(
                                                                                                                              v_eccP256_curve_point,
                                                                                                                              p_encrypted_sym_key, 
                                                                                                                              p_authentication_vector
                                                                                                                              )));
      }
      p_ieee1609dot2_signed_and_encrypted_data := valueof(
                                                          m_etsiTs103097Data_encrypted(
                                                                                       m_encryptedData(
                                                                                                       {
                                                                                                        m_recipientInfo_certRecipInfo(
                                                                                                                                      m_pKRecipientInfo(
                                                                                                                                                        v_recipientId,
                                                                                                                                                        v_encrypted_data_encryption_key
                                                                                                                                                        ))
                                                                                                        },
                                                                                                       m_symmetricCiphertext_aes128ccm(
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                       m_aesCcmCiphertext(
                                                                                                                                                          p_nonce,
                                                                                                                                                          v_encrypted_request
                                                                                                                                                          )
                                                                                                                                       )
                                                                                                      )
                                                                                       )
                                                          );
      
      // The 'p_request_hash' shall be the SHA256 digest of the OER representation of the topmost EtsiTs103097Data-Encoded structure
      v_enc_value := encvalue(p_ieee1609dot2_signed_and_encrypted_data);
      p_request_hash := f_hashWithSha256(bit2oct(v_enc_value));
      log("f_build_pki_secured_request_message: p_request_hash= ", p_request_hash);
      
      log("<<< f_build_pki_secured_request_message: ", p_ieee1609dot2_signed_and_encrypted_data);
      return true;
    } // End of function f_build_pki_secured_request_message
    
    function f_build_pki_secured_request_message_for_authorization(
                                                                   in HashedId8 p_recipientId,
                                                                   in octetstring p_public_key_compressed,
                                                                   in integer p_compressed_mode,
                                                                   in octetstring p_salt,
                                                                   in octetstring p_pki_message,
                                                                   in SignAlgorithm p_enc_algorithm,
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                   out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data,
                                                                   out Oct16 p_aes_sym_key,
                                                                   out Oct16 p_encrypted_sym_key,
                                                                   out Oct16 p_authentication_vector,
                                                                   out Oct12 p_nonce,
                                                                   out Oct32 p_request_hash
                                                                   ) return boolean {
      // Local variables
      var Ieee1609Dot2Data v_unsecured_data;
      var octetstring v_pki_message;
      var template (value) EccP256CurvePoint v_eccP256_curve_point;
      var HashedId8 v_recipientId;
      var octetstring v_public_compressed_ephemeral_key;
      var integer v_public_compressed_ephemeral_mode;
      var octetstring v_encrypted_request;
      var EncryptedDataEncryptionKey v_encrypted_data_encryption_key;
      var bitstring v_enc_value;
      
      log(">>> f_build_pki_secured_request_message_for_authorization");

      // Add Ieee1609Dot2Data layer
      v_unsecured_data := valueof(m_etsiTs103097Data_unsecured(p_pki_message));
      v_pki_message := bit2oct(encvalue(v_unsecured_data));
      
      // Encrypt encode EtsiTs103097Data-Signed data structure
      if (p_enc_algorithm == e_nist_p256) {
        v_encrypted_request := f_encryptWithEciesNistp256WithSha256(v_pki_message, p_public_key_compressed, p_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce);
      } else if (p_enc_algorithm == e_brainpool_p256_r1) {
        v_encrypted_request := f_encryptWithEciesBrainpoolp256r1WithSha256(v_pki_message, p_public_key_compressed, p_compressed_mode, p_salt, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce);
      } else {
        log("f_build_pki_secured_request_message_for_authorization: Wrong encryption variant");
        return false;
      }
      log("f_build_pki_secured_request_message_for_authorization: p_aes_sym_key= ", p_aes_sym_key);
      log("f_build_pki_secured_request_message_for_authorization: p_encrypted_sym_key= ", p_encrypted_sym_key);
      log("f_build_pki_secured_request_message_for_authorization: p_authentication_vector= ", p_authentication_vector);
      log("f_build_pki_secured_request_message_for_authorization: p_nonce= ", p_nonce);
      log("f_build_pki_secured_request_message_for_authorization: p_recipientId= ", p_recipientId);
      if (p_recipientId == int2oct(0, 8)) {
        log("f_build_pki_secured_request_message_for_authorization: f_hashWithSha256(v_encrypted_sym_key)= ", f_hashWithSha256(p_encrypted_sym_key));
        v_recipientId := f_hashedId8FromSha256(f_hashWithSha256(p_encrypted_sym_key));
      } else {
        v_recipientId := p_recipientId;
      }
      log("f_build_pki_secured_request_message_for_authorization: v_recipientId= ", v_recipientId);
      // Fill Certificate template with the public compressed keys (canonical form)
      if (v_public_compressed_ephemeral_mode == 0) {
        v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_compressed_ephemeral_key));
      } else {
        v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_compressed_ephemeral_key));
      }
      if (p_enc_algorithm == e_nist_p256) {
        v_encrypted_data_encryption_key := valueof(
                                                   m_encryptedDataEncryptionKey_eciesNistP256(
                                                                                              m_evciesP256EncryptedKey(
                                                                                                                       v_eccP256_curve_point,
                                                                                                                       p_encrypted_sym_key, 
                                                                                                                       p_authentication_vector
                                                                                                                       )));
      } else if (p_enc_algorithm == e_brainpool_p256_r1) {
        v_encrypted_data_encryption_key := valueof(
                                                   m_encryptedDataEncryptionKey_eciesBrainpoolP256r1(
                                                                                                     m_evciesP256EncryptedKey(
                                                                                                                              v_eccP256_curve_point,
                                                                                                                              p_encrypted_sym_key, 
                                                                                                                              p_authentication_vector
                                                                                                                              )));
      }
      p_ieee1609dot2_signed_and_encrypted_data := valueof(
                                                          m_etsiTs103097Data_encrypted(
                                                                                       m_encryptedData(
                                                                                                       {
                                                                                                        m_recipientInfo_certRecipInfo(
                                                                                                                                      m_pKRecipientInfo(
                                                                                                                                                        v_recipientId,
                                                                                                                                                        v_encrypted_data_encryption_key
                                                                                                                                                        ))
                                                                                                        },
                                                                                                       m_symmetricCiphertext_aes128ccm(
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                       m_aesCcmCiphertext(
                                                                                                                                                          p_nonce,
                                                                                                                                                          v_encrypted_request
                                                                                                                                                          )
                                                                                                                                       )
                                                                                                      )
                                                                                       )
                                                          );
      
      // The 'p_request_hash' shall be the SHA256 digest of the OER representation of the topmost EtsiTs103097Data-Encoded structure
      v_enc_value := encvalue(p_ieee1609dot2_signed_and_encrypted_data);
      p_request_hash := f_hashWithSha256(bit2oct(v_enc_value));
      log("f_build_pki_secured_request_message_for_authorization: p_request_hash= ", p_request_hash);
      
      log("<<< f_build_pki_secured_request_message_for_authorization: ", p_ieee1609dot2_signed_and_encrypted_data);
      return true;
    } // End of function f_build_pki_secured_request_message_for_authorization
    
    /**
     * @desc Build a signed and encrypted PKI response message
     * @param p_private_key         Private key for signature
     * @param p_signer_identifier   Signer identifier for signature, could be self or certificate HashedId8
     * @param p_recipientId         Recipient identifier to be inclued in encrypted layer.
     *                              If value is int2oct(0. 8), the recipient id is the HashedId8 of the symmetric key used by the sender to encrypt the message to which the response is built
     * @param p_public_key_compressed The public compressed key (canonical form) for encryption
     * @param p_compressed_mode      The compressed mode of the public compressed key (canonical form) for encryption
     * @param p_pki_message         The PKI message to be secured
     * @param p_ieee1609dot2_signed_and_encrypted_data The secured message
     * @return true on success, false otherwise
     */
    function f_build_pki_secured_response_message(
                                                 in octetstring p_private_key,
                                                 in SignerIdentifier p_signer_identifier,
                                                 in octetstring p_pki_message,
                                                 in Oct16 p_aes_sym_key,
                                                 in Oct12 p_nonce,
                                                 out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data
                                                 ) return boolean {
      // Local variables
      var template (value) ToBeSignedData v_tbs;
      var octetstring v_tbs_signed;
      var template (value) Ieee1609Dot2Data v_ieee1609dot2_signed_data;
      var octetstring v_encoded_inner_ec_response;
      var HashedId8 v_recipientId;
      var octetstring v_encrypted_inner_ec_response;
      
      // Signed the encoded PKI message
      v_tbs := m_toBeSignedData(
                                m_signedDataPayload(
                                                    m_etsiTs103097Data_unsecured(p_pki_message)
                                                   ),
                                m_headerInfo_inner_pki_response(-, (f_getCurrentTime() * 1000)/*us*/)
                                );
      if (ischosen(p_signer_identifier.self_)) {
        v_tbs_signed := f_signWithEcdsaNistp256WithSha256(bit2oct(encvalue(v_tbs)), int2oct(0, 32), p_private_key);
      } else {
        var charstring v_certificate_id;
        var Oct32 v_hash;
        fx_readCertificateFromDigest(p_signer_identifier.digest, v_certificate_id); // TODO Add a wrapper function
        f_getCertificateHash(v_certificate_id, v_hash);
        v_tbs_signed := f_signWithEcdsaNistp256WithSha256(bit2oct(encvalue(v_tbs)), v_hash, p_private_key);
      }
      // Add the signature and create EtsiTs103097Data-Signed data structure
      v_ieee1609dot2_signed_data := m_etsiTs103097Data_signed(
                                                              m_signedData(
                                                                           sha256,
                                                                           v_tbs,
                                                                           p_signer_identifier,
                                                                           m_signature_ecdsaNistP256(
                                                                                                     m_ecdsaP256Signature(
                                                                                                                          m_eccP256CurvePoint_x_only(
                                                                                                                                                     substr(v_tbs_signed, 0, 32)
                                                                                                                                                     ),
                                                                                                                          substr(v_tbs_signed, 32, 32)
                                                                                                                          )
                                                                                                     )
                                                                           )
                                                      );
      // Encode EtsiTs103097Data-Signed data structure
      v_encoded_inner_ec_response := bit2oct(encvalue(v_ieee1609dot2_signed_data));
      v_encrypted_inner_ec_response := fx_encrypt_aes_128_ccm_test(p_aes_sym_key, p_nonce, v_encoded_inner_ec_response);
      v_recipientId := f_hashedId8FromSha256(f_hashWithSha256(p_aes_sym_key));
      log("v_recipientId= ", v_recipientId);
      // Fill Certificate template with the public compressed keys (canonical form)
      p_ieee1609dot2_signed_and_encrypted_data := valueof(
                                                          m_etsiTs103097Data_encrypted(
                                                                                       m_encryptedData(
                                                                                                       {
                                                                                                        m_recipientInfo_pskRecipInfo(
                                                                                                                                     v_recipientId
                                                                                                                                     )
                                                                                                       },
                                                                                                       m_symmetricCiphertext_aes128ccm(
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                                                                                       m_aesCcmCiphertext(
                                                                                                                                                          p_nonce,
                                                                                                                                                          v_encrypted_inner_ec_response
                                                                                                                                                         )
                                                                                                                                      )
                                                                                                      )
                                                                                       )
                                                         );
      
      log("<<< f_build_pki_secured_response_message: ", p_ieee1609dot2_signed_and_encrypted_data);
      return true;
    } // End of function f_build_pki_secured_response_message
    
    /**
     * @desc Verify the protocol element of the Pki message. 
     *       If p_check_security is set to false, only decryption and decoding of the outer message are verified.
     * @param p_private_enc_key     Private key for decryption
     * @param p_salt
     * @param p_p_ieee1609dot2_encrypted_and_signed_data
     * @param p_check_security      Set to true to verify PKI protocol element such as signatures...
     * @param p_request_hash        The request hash for to be used to build the response
     * @param p_etsi_ts_102941_data The EtsiTs102941Data message
     * @param p_aes_enc_key         The AES 128 encrytion key to be used to encrypt the response
     * @return true on success, false otherwise
     */
    function f_verify_pki_request_message(
                                          in Oct32 p_private_enc_key,
                                          in Oct32 p_salt,
                                          in octetstring p_issuer,
                                          in Ieee1609Dot2Data p_ieee1609dot2_encrypted_and_signed_data,
                                          in boolean p_check_security := true,
                                          out Oct16 p_request_hash,
                                          out EtsiTs102941Data p_etsi_ts_102941_data,
                                          out Oct16 p_aes_enc_key
                                          ) return boolean {
      // Local variables
      var bitstring v_msg_bit;
      var octetstring v_msg;
      var Ieee1609Dot2Data v_ieee1609dot2_signed_data;
      var Certificate v_certificate;
      var charstring v_certificate_id;

      log(">>> f_verify_pki_request_message: p_private_enc_key= ", p_private_enc_key);
      log(">>> f_verify_pki_request_message: p_salt= ", p_salt);
      log(">>> f_verify_pki_request_message: p_issuer= ", p_issuer);
      log(">>> f_verify_pki_request_message: p_ieee1609dot2_encrypted_and_signed_data= ", p_ieee1609dot2_encrypted_and_signed_data);
      
      // 1. Calculate the request Hash
      v_msg := bit2oct(encvalue(p_ieee1609dot2_encrypted_and_signed_data));
      log("f_verify_pki_request_message: Encoded request: ", v_msg);
      p_request_hash := substr(f_hashWithSha256(v_msg), 0, 16);
      log("f_verify_pki_request_message: p_request_hash= ", p_request_hash);
 
      // 2. Decrypt the InnerEcRequest
      log("f_verify_pki_request_message: p_private_enc_key= ", p_private_enc_key);
      if (f_decrypt(p_private_enc_key, p_ieee1609dot2_encrypted_and_signed_data, p_salt, v_ieee1609dot2_signed_data, p_aes_enc_key) == false) {
        log("f_verify_pki_request_message: Failed to decrypt message");
        return false;
      }
      log("f_verify_pki_request_message: v_ieee1609dot2_signed_data= ", v_ieee1609dot2_signed_data);
      log("f_verify_pki_request_message: p_aes_enc_key= ", p_aes_enc_key);

      // 3. Check basics security
      log(
          match(
                v_ieee1609dot2_signed_data,
                mw_etsiTs103097Data_signed(
                                           mw_signedData(
                                                         -,
                                                         mw_toBeSignedData(
                                                                           mw_signedDataPayload,
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                                                           )
                                                         )
                                )));
      if (match(v_ieee1609dot2_signed_data, mw_etsiTs103097Data_signed(mw_signedData(-, mw_toBeSignedData(mw_signedDataPayload)))) == false) {
        log("f_verify_pki_request_message: Failed to check basic security");
        if (p_check_security == true) {
          return false;
        }
      }
      
      // 4. Verifiy signature
      log("f_verify_pki_request_message: v_ieee1609dot2_signed_data.content.signedData.tbsData= ", v_ieee1609dot2_signed_data.content.signedData.tbsData);
      v_msg := bit2oct(encvalue(v_ieee1609dot2_signed_data.content.signedData.tbsData));
      log("f_verify_pki_request_message: v_msg= ", v_msg);
      if (p_issuer == ''O) { // self
        log("f_verify_pki_request_message: Issuer is self, check outer signature using IUT public key (PICS_ITS_S_SIGN_xxx_PUBLIC_KEY)");
        var PublicVerificationKey v_verification_key;
        
        log("f_verify_pki_request_message: PX_VE_ALG=", PX_VE_ALG);
        if (PX_VE_ALG == e_nist_p256) {
          if (PICS_ITS_S_SIGN_NISTP256_PUBLIC_KEY[0] == '02'O) {
            v_verification_key.ecdsaNistP256.compressed_y_0 := substr(PICS_ITS_S_SIGN_NISTP256_PUBLIC_KEY, 1, 32);
          } else {
            v_verification_key.ecdsaNistP256.compressed_y_1 := substr(PICS_ITS_S_SIGN_NISTP256_PUBLIC_KEY, 1, 32);
          }
        } else if (PX_VE_ALG == e_brainpool_p256_r1) {
          if (PICS_ITS_S_SIGN_BRAINPOOLP256r1_PUBLIC_KEY[0] == '02'O) {
            v_verification_key.ecdsaBrainpoolP256r1.compressed_y_0 := substr(PICS_ITS_S_SIGN_BRAINPOOLP256r1_PUBLIC_KEY, 1, 32);
          } else {
            v_verification_key.ecdsaBrainpoolP256r1.compressed_y_1 := substr(PICS_ITS_S_SIGN_BRAINPOOLP256r1_PUBLIC_KEY, 1, 32);
          }
        } else if (PX_VE_ALG == e_brainpool_p384_r1) {
          if (PICS_ITS_S_SIGN_BRAINPOOLP384r1_PUBLIC_KEY[0] == '02'O) {
            v_verification_key.ecdsaBrainpoolP384r1.compressed_y_0 := substr(PICS_ITS_S_SIGN_BRAINPOOLP384r1_PUBLIC_KEY, 1, 48);
          } else {
            v_verification_key.ecdsaBrainpoolP384r1.compressed_y_1 := substr(PICS_ITS_S_SIGN_BRAINPOOLP384r1_PUBLIC_KEY, 1, 48);
          }
        }
        log("f_verify_pki_request_message: v_verification_key=", v_verification_key);
        if (f_verifyEcdsa(v_msg, int2oct(0, 32), v_ieee1609dot2_signed_data.content.signedData.signature_, v_verification_key) == false) {
          if (p_check_security == true) {
            return false;
          }
        }
        //return false;
      } else {
        if (f_getCertificateFromDigest(f_hashedId8FromSha256(p_issuer), v_certificate, v_certificate_id) == false) {
          if (p_check_security == true) {
            return false;
          }
        }
        log("f_verify_pki_request_message: v_certificate= ", v_certificate);
        if (f_verifyEcdsa(v_msg, p_issuer, v_ieee1609dot2_signed_data.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey) == false) {
          if (p_check_security == true) {
            return false;
          }
        }
      }
      
      // 4. Return the PKI message
      log("f_verify_pki_request_message: v_ieee1609dot2_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData= ", v_ieee1609dot2_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData);
      v_msg_bit := oct2bit(v_ieee1609dot2_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData);
      if (decvalue(v_msg_bit, p_etsi_ts_102941_data) != 0) {
        if (p_check_security == true) {
          return false;
        }
      }
      if (p_etsi_ts_102941_data.version != PkiProtocolVersion) {
        if (p_check_security == true) {
          return false;
        }
      }
      
      log("<<< f_verify_pki_request_message: true");
      return true;
    } // End of function f_verify_pki_request_message
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    /**
     * @desc Verify the protocol element of the Pki message. 
     *       If p_check_security is set to false, only decryption and decoding of the outer message are verified.
     * @param p_private_key         Private key for decryption
     * @param p_publicEphemeralCompressedKey
     * @param p_publicEphemeralCompressedKeyMode
     * @param p_issuer              Issuer
     * @param p_certificate         Certificate to use for verification key
     * @param p_ieee1609dot2_encrypted_and_signed_data The received encrypted and signed data
     * @param p_check_security      Set to true to verify PKI protocol element such as signatures...
     * @param p_response_type       Response type (0: InnerEcResponse, 1: InnerAtResponse...). Default: 0
     * @param p_etsi_ts_102941_data The EtsiTs102941Data message
     * @return true on success, false otherwise
     */
    function f_verify_pki_response_message(
                                           in octetstring p_private_enc_key,
                                           in Oct16 p_aes_sym_key,
                                           in Oct16 p_authentication_vector, // TODO Tobe removed
                                           in octetstring p_issuer,
                                           in Ieee1609Dot2Data p_ieee1609dot2_encrypted_and_signed_data,
                                           in boolean p_check_security := true,
                                           in integer p_response_type := 0,
                                           out EtsiTs102941Data p_etsi_ts_102941_data
                                           ) return boolean {
      // Local variables
      var octetstring v_public_enc_key;
      var integer v_compressed_enc_key_mode;
      var octetstring v_plain_message;
      var Ieee1609Dot2Data v_ieee1609dot2_signed_data;
      var Certificate v_certificate;
      var charstring v_certificate_id;
      var bitstring v_etsi_ts_102941_data_msg;
      var bitstring v_tbs;
      var boolean v_ret;
      
      log(">>> f_verify_pki_response_message: p_private_enc_key= ", p_private_enc_key);
      log(">>> f_verify_pki_response_message: p_aes_sym_key= ", p_aes_sym_key);
      log(">>> f_verify_pki_response_message: p_authentication_vector= ", p_authentication_vector);
      log(">>> f_verify_pki_response_message: p_issuer= ", p_issuer);
      log(">>> f_verify_pki_response_message: p_check_security= ", p_check_security);
      log(">>> f_verify_pki_response_message: p_response_type= ", p_response_type);
      
      // TODO Check p_ieee1609dot2_encrypted_and_signed_data.content.encryptedData.recipients[0].pskRecipInfo. See IEEE Std 1609.2-2017 Clause 6.3.34 PreSharedKeyRecipientInfo
      
      // 1. Decrypt the data
      v_plain_message := fx_decrypt_aes_128_ccm_test(p_aes_sym_key, p_ieee1609dot2_encrypted_and_signed_data.content.encryptedData.ciphertext.aes128ccm.nonce, p_ieee1609dot2_encrypted_and_signed_data.content.encryptedData.ciphertext.aes128ccm.ccmCiphertext);
      if (isbound(v_plain_message) == false) {
        return false;
      }
      log("f_verify_pki_response_message: v_plain_message= ", v_plain_message);

      // 2. Decode it
      v_tbs := oct2bit(v_plain_message);
      if (decvalue(v_tbs, v_ieee1609dot2_signed_data) != 0) {
        return false;
      }
      log("f_verify_pki_response_message: v_ieee1609dot2_signed_data= ", v_ieee1609dot2_signed_data);
      
      // 3. Check the signature
      log("f_verify_pki_response_message: v_ieee1609dot2_signed_data.content.signedData.tbsData= ", v_ieee1609dot2_signed_data.content.signedData.tbsData);
      v_tbs := encvalue(v_ieee1609dot2_signed_data.content.signedData.tbsData);
      if (f_getCertificateFromDigest(v_ieee1609dot2_signed_data.content.signedData.signer.digest, v_certificate, v_certificate_id) == false) {
        if (p_check_security == true) {
          return false;
        }
      }
      if (f_verifyEcdsa(bit2oct(v_tbs), p_issuer, v_ieee1609dot2_signed_data.content.signedData.signature_, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey) == false) {
        if (p_check_security == true) {
          return false;
        }
      }

      // 4. Verify EtsiTs103097Data-Signed HeaderInfo
      // TODO Parameter p_response_type seems to be useless
      if ((p_response_type == 0) or (p_response_type == 1)) { // InnerEcResponse & InnerAtResponse
        log("f_verify_pki_response_message: headerInfo matching= ", match(v_ieee1609dot2_signed_data.content.signedData.tbsData.headerInfo, mw_headerInfo_inner_pki_response));
        if (match(v_ieee1609dot2_signed_data.content.signedData.tbsData.headerInfo, mw_headerInfo_inner_pki_response) == false) {
          if (p_check_security == true) {
            return false;
          }
        }
      } // else, no check
      
      // 5. Return the PKI message
      log("f_verify_pki_response_message: v_ieee1609dot2_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData= ", v_ieee1609dot2_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData);
      v_etsi_ts_102941_data_msg := oct2bit(v_ieee1609dot2_signed_data.content.signedData.tbsData.payload.data.content.unsecuredData);
      if (decvalue(v_etsi_ts_102941_data_msg, p_etsi_ts_102941_data) != 0) {
        return false;
      }

      if (p_etsi_ts_102941_data.version != PkiProtocolVersion) {
        return false;
      }
      
      return true;
    } // End of function f_verify_pki_response_message
    
    function f_verify_repeated_request(
                                       in HttpMessage p_request_1,
                                       in HttpMessage p_request_2
                                       ) return boolean {

      return false;
    } // End of function f_verify_repeated_request
    
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    /**
     * @desc Verify the EC certificate generated by the EA entity
     * @param p_ec_certificate        The new EC certificate
     * @param p_ea_certificate        The certificate issuer
     * @param p_public_key_compressed The public compressed key (canonical form) generated for the InnerEcRequest
     * @param p_compressed_mode       The public compressed key mode
     * @return true on success, false otherwise
     */
    function f_verify_ec_certificate(
                                     in Certificate p_ec_certificate,
                                     in Certificate p_ea_certificate,
                                     in HashedId8 p_ea_hashed_id8,
                                     in octetstring p_public_key_compressed,
                                     in integer p_compressed_mode,
                                     out HashedId8 p_ec_cert_hashed_id8
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                     ) return boolean {
      var bitstring v_encoded_cert;
      var Oct32 v_ec_cert_hash;
      
      // Calculate the HashedId8 of the whole certificate
      v_encoded_cert := encvalue(p_ec_certificate);
      v_ec_cert_hash := f_hashWithSha256(bit2oct(v_encoded_cert));
      log("f_verify_ec_certificate: ==> EC certificate Hash: ", v_ec_cert_hash);
      p_ec_cert_hashed_id8 := f_hashedId8FromSha256(v_ec_cert_hash);
      log("f_verify_ec_certificate: ==> EC certificate HashedId8: ", p_ec_cert_hashed_id8);
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      
      // Check the signer
      log("f_verify_ec_certificate: Check the signer: ", match(p_ec_certificate.issuer, m_issuerIdentifier_sha256AndDigest(p_ea_hashed_id8)));
      log("f_verify_ec_certificate: Check the signer: ", match(p_ec_certificate.issuer, m_issuerIdentifier_sha384AndDigest(p_ea_hashed_id8)));
      if (
          (match(p_ec_certificate.issuer, m_issuerIdentifier_sha256AndDigest(p_ea_hashed_id8)) == false) and
          (match(p_ec_certificate.issuer, m_issuerIdentifier_sha384AndDigest(p_ea_hashed_id8)) == false)
          ) {
        log("f_verify_ec_certificate: Wrong issuer");
        return false;
      }
      
      // Check EC certificate signature
      if (f_verifyCertificateSignatureWithPublicKey(p_ec_certificate, p_ea_certificate.toBeSigned.verifyKeyIndicator.verificationKey) == false) {
        log("f_verify_ec_certificate: Signature not verified");
        return false;
      }
      
      // TODO Check that requested information are present
      
      if (f_verifySspPermissions(p_ec_certificate.toBeSigned.appPermissions, p_ea_certificate.toBeSigned.appPermissions) == false) {
        log("f_verify_ec_certificate: Ssp permissions not verified");
        return false;
      }
      
      return true;
    } // End of function f_verify_ec_certificate
    
    /**
     * @desc Verify the generated AT certificate 
     * @param p_at_certificate        The new AT certificate
     * @param p_ea_certificate        The certificate issuer
     * @param p_public_key_compressed The public compressed key (canonical form) generated for the InnerAtRequest
     * @param p_compressed_mode       The public compressed key mode
     * @return true on success, false otherwise
     */
    function f_verify_at_certificate(
                                     in Certificate p_at_certificate,
                                     in Certificate p_aa_certificate,
                                     in octetstring p_public_key_compressed,
                                     in integer p_compressed_mode
                                     ) return boolean {
      var bitstring v_encoded_cert;
      var HashedId8 v_at_cert_hashed_id8;
      
      // Calculate the HashedId8 of the whole certificate
      v_encoded_cert := encvalue(p_at_certificate);
      v_at_cert_hashed_id8 := f_hashedId8FromSha256(f_hashWithSha256(bit2oct(v_encoded_cert)));
      log("f_verify_at_certificate: EC certificate HashedId8: ", v_at_cert_hashed_id8);
      
      // Check the signer
      log("f_verify_at_certificate: ", match(p_at_certificate.issuer, mw_issuerIdentifier_self()));
      if (match(p_at_certificate.issuer, mw_issuerIdentifier_self)) {
        return false;
      }
      
      // Check EC certificate signature
      if (f_verifyCertificateSignatureWithPublicKey(p_at_certificate, p_aa_certificate.toBeSigned.verifyKeyIndicator.verificationKey) == false) {
        log("f_verify_at_certificate: Signature not verified");
        return false;
      }
      
      // TODO Check that requested information are present
      
      if (f_verifySspPermissions(p_aa_certificate.toBeSigned.appPermissions, p_at_certificate.toBeSigned.appPermissions) == false) {
        log("f_verify_ec_certificate: Ssp permissions not verified");
        return false;
      }
      
      return true;
    } // End of function f_verify_at_certificate
    
  } // End of group inner_ec_xxx

  group altsteps {
    
    altstep a_default_pki_http() runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(
                                                      mw_http_response(
                                                                       mw_http_response_ko
                                                                       )) {
        tc_ac.stop;
        
        log("*** " & testcasename() & ": FAIL: Unexpected message received ***");
        f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error);
      }
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(mw_http_request) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Request received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(mw_http_response) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Response received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP message received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [] a_shutdown() {
        log("*** a_default: INFO: TEST COMPONENT NOW STOPPING ITSELF! ***");
        stop;
      }
    } // End of altstep a_default_pki_http
    
    altstep a_default_pki_http_ec() runs on ItsPkiHttp {
      [PICS_MULTIPLE_END_POINT] httpEcPort.receive(
                                                   mw_http_response(
                                                                    mw_http_response_ko
                                                                    )) {
        tc_ac.stop;
        
        log("*** " & testcasename() & ": FAIL: Unexpected message received ***");
        f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpEcPort.receive(mw_http_request) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Request received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpEcPort.receive(mw_http_response) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Response received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpEcPort.receive {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP message received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [] a_shutdown() {
        log("*** a_default: INFO: TEST COMPONENT NOW STOPPING ITSELF! ***");
        stop;
      }
    } // End of altstep a_default_pki_http_ec
    
    altstep a_default_pki_http_atv() runs on ItsPkiHttp {
      [PICS_MULTIPLE_END_POINT] httpAtVPort.receive(
                                                   mw_http_response(
                                                                    mw_http_response_ko
                                                                    )) {
        tc_ac.stop;
        
        log("*** " & testcasename() & ": FAIL: Unexpected message received ***");
        f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpAtVPort.receive(mw_http_request) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Request received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpAtVPort.receive(mw_http_response) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Response received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpAtVPort.receive {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP message received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [] a_shutdown() {
        log("*** a_default: INFO: TEST COMPONENT NOW STOPPING ITSELF! ***");
        stop;
      }
    } // End of altstep a_default_pki_http_atv
    
    altstep a_default_pki_http_at() runs on ItsPkiHttp {
      [PICS_MULTIPLE_END_POINT] httpAtPort.receive(
                                                   mw_http_response(
                                                                    mw_http_response_ko
                                                                    )) {
        tc_ac.stop;
        
        log("*** " & testcasename() & ": FAIL: Unexpected message received ***");
        f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpAtPort.receive(mw_http_request) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Request received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpAtPort.receive(mw_http_response) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Response received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpAtPort.receive {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP message received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [] a_shutdown() {
        log("*** a_default: INFO: TEST COMPONENT NOW STOPPING ITSELF! ***");
        stop;
      }
    } // End of altstep a_default_pki_http_at

    altstep a_default_pki_http_ca() runs on ItsPkiHttp {
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(
                                                   mw_http_response(
                                                                    mw_http_response_ko
                                                                    )) {
        tc_ac.stop;
        
        log("*** " & testcasename() & ": FAIL: Unexpected message received ***");
        f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(mw_http_request) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Request received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(mw_http_response) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Response received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP message received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [] a_shutdown() {
        log("*** a_default: INFO: TEST COMPONENT NOW STOPPING ITSELF! ***");
        stop;
      }
    } // End of altstep a_default_pki_http_ca

    altstep a_default_pki_http_tlm() runs on ItsPkiHttp {
      [PICS_MULTIPLE_END_POINT] httpTlmPort.receive(
                                                   mw_http_response(
                                                                    mw_http_response_ko
                                                                    )) {
        tc_ac.stop;
        
        log("*** " & testcasename() & ": FAIL: Unexpected message received ***");
        f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpTlmPort.receive(mw_http_request) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Request received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpTlmPort.receive(mw_http_response) {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP Response received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [PICS_MULTIPLE_END_POINT] httpTlmPort.receive {
        tc_ac.stop;
        log("*** a_default: ERROR: Unexpected HTTP message received ***");
        f_selfOrClientSyncAndVerdict("error", e_error);
      }
      [] a_shutdown() {
        log("*** a_default: INFO: TEST COMPONENT NOW STOPPING ITSELF! ***");
        stop;
      }
    } // End of altstep a_default_pki_http_tlm

    altstep a_await_ec_http_request_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_request
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        log("a_await_ec_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpEcPort.receive(p_http_message) -> value p_request {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        log("a_await_ec_http_request_from_iut: Received message on httpEcPort");
      }
    } // End of altstep a_await_ec_http_request_from_iut
    
    altstep a_await_ec_http_response_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_response
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_response {
        log("a_await_ec_http_response_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpEcPort.receive(p_http_message) -> value p_response {
        log("a_await_ec_http_response_from_iut: Received message on httpEcPort");
      }
    } // End of altstep a_await_ec_http_response_from_iut
    
    altstep a_await_at_http_request_from_iut(
                                             template HttpMessage p_http_message,
                                             out HttpMessage p_request
                                             ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
        log("a_await_at_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpAtPort.receive(p_http_message) -> value p_request {
        log("a_await_at_http_request_from_iut: Received message on httpAtPort");
      }
    } // End of altstep a_await_at_http_request_from_iut
    
ASN.1 Documenter's avatar
ASN.1 Documenter committed
    altstep a_await_at_http_response_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_response
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_response {
        log("a_await_at_http_response_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpAtPort.receive(p_http_message) -> value p_response {
        log("a_await_at_http_response_from_iut: Received message on httpAtPort");
      }
    } // End of altstep a_await_at_http_response_from_iut
    
    altstep a_await_atv_http_request_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_request
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
        log("a_await_atv_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpAtVPort.receive(p_http_message) -> value p_request {
        log("a_await_avt_http_request_from_iut: Received message on httpAtVPort");
      }
    } // End of altstep a_await_atv_http_request_from_iut
    
    altstep a_await_atv_http_response_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_response
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_response {
        log("a_await_atv_http_response_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpAtVPort.receive(p_http_message) -> value p_response {
        log("a_await_avt_http_response_from_iut: Received message on httpAtVPort");
      }
    } // End of altstep a_await_atv_http_response_from_iut
    
    altstep a_await_dc_http_request_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_request
ASN.1 Documenter's avatar
ASN.1 Documenter committed
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
ASN.1 Documenter's avatar
ASN.1 Documenter committed
        log("a_await_dc_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(p_http_message) -> value p_request {
        log("a_await_dc_http_request_from_iut: Received message on httpCaPort");
ASN.1 Documenter's avatar
ASN.1 Documenter committed
      }
    } // End of altstep a_await_dc_http_request_from_iut
    
    altstep a_await_ctl_http_request_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_request
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
        log("a_await_ctl_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(p_http_message) -> value p_request {
        log("a_await_ctl_http_request_from_iut: Received message on httpCaPort");
      }
    } // End of altstep a_await_ctl_http_request_from_iut
    
    altstep a_await_crl_http_request_from_iut(
                                              template HttpMessage p_http_message,
                                              out HttpMessage p_request
                                              ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
        log("a_await_crl_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(p_http_message) -> value p_request {
        log("a_await_crl_http_request_from_iut: Received message on httpCaPort");
      }
    } // End of altstep a_await_crl_http_request_from_iut
    
    altstep a_await_cpoc_http_request_from_iut(
                                               template HttpMessage p_http_message,
                                               out HttpMessage p_request
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
        log("a_await_cpoc_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(p_http_message) -> value p_request {
        log("a_await_cpoc_http_request_from_iut: Received message on httpCaPort");
      }
    } // End of altstep a_await_cpoc_http_request_from_iut
    
    altstep a_await_any_http_request_from_iut(
                                               template HttpMessage p_http_message,
                                               out HttpMessage p_request
                                               ) runs on ItsPkiHttp {
      [not(PICS_MULTIPLE_END_POINT)] httpPort.receive(p_http_message) -> value p_request {
        log("a_await_any_http_request_from_iut: Received message on httpPort");
      }
      [PICS_MULTIPLE_END_POINT] httpCaPort.receive(p_http_message) -> value p_request {
        log("a_await_any_http_request_from_iut: Received message on httpEcPort");
      }
    } // End of altstep a_await_any_http_request_from_iut
    
ASN.1 Documenter's avatar
ASN.1 Documenter committed
  } // End of group altsteps
  
} // End of module LibItsPki_Functions