/** * @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; // 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 EtsiTs103097Module language "ASN.1:1997" all; import from ITS_Container language "ASN.1:1997" all; 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; // LibItsHttp import from LibItsHttp_TypesAndValues all; import from LibItsHttp_Templates all; import from LibItsHttp_BinaryTemplates all; import from LibItsHttp_Functions all; import from LibItsHttp_TestSystem all; // 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_cfMtcUp( out ItsPkiItss p_itss, out ItsPkiHttp p_pki ) runs on ItsMtc { p_itss := ItsPkiItss.create("IUT") alive; p_pki := ItsPkiHttp.create("TS") alive; connect(self:syncPort, mtc:syncPort); connect(p_itss:syncPort, self:syncPort); connect(p_pki:syncPort, self:syncPort); } /** * @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 /* TITAN TODO: 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??? // 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); 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); // Setup AA certificate shared with PKI AA entity f_readCertificate(p_aa_certificate_id, vc_aaCertificate); f_getCertificateDigest(p_aa_certificate_id, vc_aaHashedId8); f_getCertificateHash(p_aa_certificate_id, vc_aaWholeHash); log("f_cfHttpUp: vc_aaHashedId8= ", vc_aaHashedId8); log("f_cfHttpUp: vc_aaWholeHash= ", vc_aaWholeHash); 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 function f_cfUp_itss( in charstring p_certificate_id := "CERT_TS_A_EA" // TODO Use a constant ) runs on ItsPkiItss /* TITAN TODO: system ItsPkiItssSystem */ { 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_cfMtcDown( 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); p_itss.done; p_pki.done; } /** * @desc Deletes default configuration */ function f_cfHttpDown() runs on ItsPkiHttp /* TITAN TODO: system ItsPkiHttpSystem */ { 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_cfDown_itss() runs on ItsPkiItss /* TITAN TODO: 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 { // Local variables // Load certificates if(not(f_loadCertificates(PX_IUT_SEC_CONFIG_NAME))) { log("*** INFO: TEST CASE NOW STOPPING ITSELF! ***"); setverdict(inconc); stop; } // f_prepareCertificates(p_certificate_id, vc_aaCertificate, vc_atCertificate); } // 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 { timer tc_wait := PX_TAC; 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 } // 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 { if (PX_EC_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_EC_ALG == e_brainpool_p256_r1) { f_generate_key_pair_brainpoolp256(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_signWithEcdsa( in octetstring p_toBeSignedSecuredMessage, in octetstring p_certificateIssuer, in octetstring p_privateKey ) return octetstring { if (PX_VE_ALG == e_nist_p256) { return f_signWithEcdsaNistp256WithSha256(p_toBeSignedSecuredMessage, p_certificateIssuer, p_privateKey); } else if (PX_VE_ALG == e_brainpool_p256_r1) { return f_signWithEcdsaBrainpoolp256WithSha256(p_toBeSignedSecuredMessage, p_certificateIssuer, p_privateKey); } else if (PX_VE_ALG == e_brainpool_p384_r1) { return f_signWithEcdsaBrainpoolp384WithSha384(p_toBeSignedSecuredMessage, p_certificateIssuer, p_privateKey); } return ''O; } // End of function f_signWithEcdsa function f_verifyEcdsa( in octetstring p_tbs, in octetstring p_issuer, in Signature p_signature_, in PublicVerificationKey p_verification_key ) return boolean { var boolean v_ret := false; log(" >>> f_verifyEcdsa: p_tbs", p_tbs); log(" >>> f_verifyEcdsa: p_issuer", p_issuer); log(" >>> f_verifyEcdsa: p_signature_", p_signature_); log(" >>> f_verifyEcdsa: p_verification_key", p_verification_key); if (ischosen(p_verification_key.ecdsaNistP256)) { if (ischosen(p_verification_key.ecdsaNistP256.compressed_y_0)) { v_ret := f_verifyWithEcdsaNistp256WithSha256( p_tbs, p_issuer, p_signature_.ecdsaNistP256Signature.rSig.x_only & p_signature_.ecdsaNistP256Signature.sSig, p_verification_key.ecdsaNistP256.compressed_y_0, 0); } else { v_ret := f_verifyWithEcdsaNistp256WithSha256( p_tbs, p_issuer, p_signature_.ecdsaNistP256Signature.rSig.x_only & p_signature_.ecdsaNistP256Signature.sSig, p_verification_key.ecdsaNistP256.compressed_y_1, 1); } } else if (ischosen(p_verification_key.ecdsaBrainpoolP256r1)) { if (ischosen(p_verification_key.ecdsaBrainpoolP256r1.compressed_y_0)) { v_ret := f_verifyWithEcdsaBrainpoolp256WithSha256( p_tbs, p_issuer, p_signature_.ecdsaBrainpoolP256r1Signature.rSig.x_only & p_signature_.ecdsaBrainpoolP256r1Signature.sSig, p_verification_key.ecdsaBrainpoolP256r1.compressed_y_0, 0); } else { v_ret := f_verifyWithEcdsaBrainpoolp256WithSha256( p_tbs, p_issuer, p_signature_.ecdsaBrainpoolP256r1Signature.rSig.x_only & p_signature_.ecdsaBrainpoolP256r1Signature.sSig, p_verification_key.ecdsaBrainpoolP256r1.compressed_y_1, 1); } } else if (ischosen(p_verification_key.ecdsaBrainpoolP384r1)) { if (ischosen(p_verification_key.ecdsaBrainpoolP384r1.compressed_y_0)) { v_ret := f_verifyWithEcdsaBrainpoolp384WithSha384( p_tbs, p_issuer, p_signature_.ecdsaBrainpoolP384r1Signature.rSig.x_only & p_signature_.ecdsaBrainpoolP384r1Signature.sSig, p_verification_key.ecdsaBrainpoolP384r1.compressed_y_0, 0); } else { v_ret := f_verifyWithEcdsaBrainpoolp384WithSha384( p_tbs, p_issuer, p_signature_.ecdsaBrainpoolP384r1Signature.rSig.x_only & p_signature_.ecdsaBrainpoolP384r1Signature.sSig, p_verification_key.ecdsaBrainpoolP384r1.compressed_y_1, 1); } } return v_ret; } // End of function f_verifyEcdsa } // 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"); 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_enrolment_request: ==> EC verification private key: ", p_private_key); log ("f_http_build_enrolment_request: ==> EC verification public compressed key: ", p_public_key_compressed); log ("f_http_build_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_inner_ec_request: ERROR: Failed to generate InnerEcRequestSignedForPop ***"); f_selfOrClientSyncAndVerdict("error", e_error); } log("f_http_build_enrolment_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); } if (PICS_SEC_FIXED_KEYS) { // Debug mode: Use fixed values v_public_enc_key := 'DD4F6B0DF57C6E3BD0E32B565CACA1D858CEB08A5C2BBAB2C23E203C6DE697FF'O; v_compressed_enc_key_mode := 0; } 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_eaWholeHash; if (PICS_SECPKI_REENROLMENT == false) { // This is the first enrolment, we used Factory keys v_result := f_build_pki_secured_request_message_signed_with_pop(PICS_ITS_S_SIGN_NITSP256_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))), 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: ", PX_EC_PRIVATE_KEY); log("f_http_build_inner_ec_request: v_ec_hashed_id8: ", PX_EC_HASHED_ID8); v_result := f_build_pki_secured_request_message_signed_with_pop(PX_EC_PRIVATE_KEY, valueof(m_signerIdentifier_digest(PX_EC_HASHED_ID8)), PX_EC_HASHED_ID8/*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))), p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash); } 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_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; 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 { 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])); } // 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_eaWholeHash; if (PICS_SECPKI_REENROLMENT == false) { // This is the first enrolment, we used Factory keys v_ret_code := f_build_pki_secured_request_message_signed_with_pop(PICS_ITS_S_SIGN_NITSP256_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))), 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: ", PX_EC_PRIVATE_KEY); log("f_http_build_inner_ec_request: v_ec_hashed_id8: ", PX_EC_HASHED_ID8); v_ret_code := f_build_pki_secured_request_message_signed_with_pop(PX_EC_PRIVATE_KEY, valueof(m_signerIdentifier_digest(PX_EC_HASHED_ID8)), PX_EC_HASHED_ID8/*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))), p_ieee1609dot2_signed_and_encrypted_data, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, p_request_hash); } 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 InnerEcRequest p_inner_ec_request, 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 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 InnerEcResponse v_inner_ec_response; var EtsiTs103097Certificate v_ec_certificate; 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) { v_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(p_inner_ec_request, p_private_key, p_digest, v_ec_certificate) == false) { log("f_http_build_inner_ec_response: Failed to generate the certificate"); v_inner_ec_response := valueof( m_innerEcResponse_ko( p_request_hash, incompleterequest ) ); } else { v_inner_ec_response := valueof( m_innerEcResponse_ok( p_request_hash, v_ec_certificate ) ); } } // Secure the response log("f_http_build_inner_ec_response: v_inner_ec_response= ", v_inner_ec_response); v_msg := bit2oct(encvalue(v_inner_ec_response)); v_nonce := int2oct(f_getCurrentTime(), 32); // 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"); v_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_eaCertificate, 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 AuthorizationValidationRequest ***"); 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); } if (PICS_SEC_FIXED_KEYS) { // Debug mode: Use fixed values v_public_enc_key := 'DD4F6B0DF57C6E3BD0E32B565CACA1D858CEB08A5C2BBAB2C23E203C6DE697FF'O; v_compressed_enc_key_mode := 0; } 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_aaWholeHash; log("*** f_http_build_authorization_request: p_salt: ", p_salt); if (PX_AUTHORIZATION_REQUEST_WITH_POP) { if(f_build_pki_secured_request_message_signed_with_pop(PICS_ITS_S_SIGN_NITSP256_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))), 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))), 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); } // End of function f_http_build_authorization_request function f_http_build_authorization_validation_request( in InnerAtRequest p_inner_at_request, 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 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; // 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 Pki 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: ERROR: 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); // Secure 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: ERROR: Non canonical EA certificate ***"); f_selfOrClientSyncAndVerdict("error", e_error); } if (PICS_SEC_FIXED_KEYS) { // Debug mode: Use fixed values v_public_enc_key := 'DD4F6B0DF57C6E3BD0E32B565CACA1D858CEB08A5C2BBAB2C23E203C6DE697FF'O; v_compressed_enc_key_mode := 0; } 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_eaWholeHash; log("*** f_http_build_authorization_validation_request: p_salt: ", p_salt); if(f_build_pki_secured_request_message_signed_with_pop(PICS_ITS_S_SIGN_NITSP256_PRIVATE_KEY, valueof(m_signerIdentifier_self), 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))), 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: ERROR: Failed to generate Authorization Request ***"); f_selfOrClientSyncAndVerdict("error", e_error); } log("*** f_http_build_authorization_validation_request: DEBUG: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data); log("*** f_http_build_authorization_validation_request: DEBUG: p_request_hash= ", p_request_hash); } // End of function f_http_build_authorization_validation_request } // 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 := '830001'O })), valueof(m_appPermissions(37, { bitmapSsp := '830001'O })) }; 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"); // 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 == e_nist_p256) { v_public_verification_key := valueof( m_publicVerificationKey_ecdsaNistP256( v_ecc_p256_curve_point )); } else if (PX_EC_ALG == 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"); 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_years(1) ), m_geographicRegion_identifiedRegion( { m_identifiedRegion_country_only(12), m_identifiedRegion_country_only(34) } ) ) ); // 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 ) return boolean { 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"); 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_ec_request.requestedSubjectAttributes.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); log("f_generate_ec_certificate_for_inner_ec_response: p_ec_certificate= ", p_ec_certificate); return true; } // End of function f_generate_ec_certificate_for_inner_ec_response function f_generate_at_certificate( in octetstring p_private_key, in InnerEcRequest p_inner_ec_request, out Certificate p_at_certificate ) return boolean { var SequenceOfPsidSsp v_appPermissions := { // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs valueof(m_appPermissions(36, { bitmapSsp := '830001'O })), valueof(m_appPermissions(37, { bitmapSsp := '830001'O })) }; 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; if (PX_EC_ALG == e_nist_p256) { v_public_verification_key := valueof( m_publicVerificationKey_ecdsaNistP256( p_inner_ec_request.publicKeys.verificationKey.ecdsaNistP256 )); } else if (PX_EC_ALG == e_brainpool_p256_r1) { v_public_verification_key := valueof( m_publicVerificationKey_ecdsaBrainpoolP256r1( p_inner_ec_request.publicKeys.verificationKey.ecdsaBrainpoolP256r1 )); } else { // Error log("f_generate_ec_certificate: Wrong encryption algorithm, check PX_EC_ALG"); 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_years(1) ), m_geographicRegion_identifiedRegion( { m_identifiedRegion_country_only(12), m_identifiedRegion_country_only(34) } ) ) ); // 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("v_cert= ", v_cert); p_at_certificate := valueof(v_cert); return true; } // End of function f_generate_at_certificate } // 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 ) return boolean { // Local variables var Oct32 v_publicKeyX; var Oct32 v_publicKeyY; var EccP256CurvePoint v_eccP256_curve_point; log (">>> f_generate_inner_ec_request"); // Generate keys for the certificate to be requested if (f_generate_key_pair(p_private_key, v_publicKeyX, v_publicKeyY, p_public_key_compressed, p_compressed_mode) == false) { log ("f_generate_inner_ec_request: failed to generate keys"); return false; } 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)); } // Build the Proof of Possession InnerEcRequest p_inner_ec_request := valueof( m_innerEcRequest( PICS_ITS_S_CANONICAL_ID, m_publicKeys( m_publicVerificationKey_ecdsaNistP256(v_eccP256_curve_point) ), m_certificateSubjectAttributes( { // ETSI TS 102 965 Table A.1: ETSI ITS standardized ITS-AIDs valueof(m_appPermissions(c_its_aid_SCR, { bitmapSsp := '00C0'O })) }, m_validityPeriod( f_getCurrentTime() / 1000, m_duration_years(1) // TODO Use PIXIT ), m_geographicRegion_identifiedRegion( { m_identifiedRegion_country_only(12), // TODO Use PIXIT m_identifiedRegion_country_only(34) // TODO Use PIXIT } ), 'C0'O // TODO Use PIXIT ) ) ); if (PICS_SECPKI_REENROLMENT) { // This is a re-enrolment, the identifier of its current valid Enrolment Credential log("f_generate_inner_ec_request: This is a re-enrolment"); p_inner_ec_request.itsId := PX_EC_HASHED_ID8; } 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_signed_for_pop( in octetstring p_private_key, in InnerEcRequest p_inner_ec_request, out Ieee1609Dot2Data p_inner_ec_request_signed_for_pop ) return boolean { // 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 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_getCurrentTimeUtc() ) ); // Signed the encoded InnerEcRequestSignedForPop 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_ea_certificate, 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 Oct8 v_ec_hashed_id8; var octetstring public_enc_key_x; var octetstring public_enc_key_y; var Oct32 v_hmac_key; var octetstring v_message_to_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; // 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(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 { p_private_enc_key := ''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: v_ec_hash= ", v_ec_hash); // Generate 32 octets length secret key v_hmac_key := f_hashWithSha256(int2oct(f_getCurrentTime(), 12)); log("f_generate_inner_at_request: v_hmac_key= ", v_hmac_key); // Generate tag based on the concatenation of verification keys & encryption keys v_message_to_tag := v_public_key_x & v_public_key_y & v_public_enc_key_x & v_public_enc_key_y; log("f_generate_inner_at_request: v_message_to_tag= ", v_message_to_tag); // FIXME encryption keys could be optional v_key_tag := fx_hmac_sha256(v_hmac_key, v_message_to_tag); // TODO Rename and use a wrapper function 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 substr(v_key_tag, 0, 16), // Calculated keyTag valueof( m_certificate_subject_attributes( // FIXME Review subjectPermissions p_ec_certificate.toBeSigned.appPermissions, p_ec_certificate.toBeSigned.certRequestPermissions, 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_getCurrentTimeUtc()) ); log("f_generate_inner_at_request: 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 if (ischosen(p_ec_certificate.signature_.ecdsaBrainpoolP384r1Signature)) { v_hashId := sha384; v_tbs_signed := f_signWithEcdsaBrainpoolp384WithSha384(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.signature_.ecdsaBrainpoolP256r1Signature)) { v_tbs_signed := f_signWithEcdsaBrainpoolp256WithSha256(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.signature_.ecdsaNistP256Signature)) { 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 thehasheId8 of the EC certificate obtained from Enrolment request v_signature ) ) ); log("f_generate_inner_at_request: 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 (PX_EC_ALG == 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; } if (PX_EC_ALG == e_nist_p256) { v_enc_signed_ec_signature := f_encryptWithEciesNistp256WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, ''O, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce, PICS_SEC_FIXED_KEYS); } else if (PX_EC_ALG == e_brainpool_p256_r1) { v_enc_signed_ec_signature := f_encryptWithEciesBrainpoolp256WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, ''O, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce, PICS_SEC_FIXED_KEYS); } else { log("f_generate_inner_at_request: Wrong encryption variant"); return false; } if (v_compressed_mode == 0) { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_public_enc_key)); } else { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_public_enc_key)); } log("f_generate_inner_at_request: v_eccP256_curve_point= ", v_eccP256_curve_point); log("f_generate_inner_at_request: v_encrypted_sym_key= ", v_encrypted_sym_key); log("f_generate_inner_at_request: v_authentication_vector= ", v_authentication_vector); v_encrypted_data_encryption_key := valueof( m_encryptedDataEncryptionKey_eciesNistP256( m_evciesP256EncryptedKey( v_eccP256_curve_point, v_encrypted_sym_key, v_authentication_vector ))); } else if (PX_EC_ALG == 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; } if (PX_EC_ALG == e_nist_p256) { v_enc_signed_ec_signature := f_encryptWithEciesNistp256WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, ''O, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce, PICS_SEC_FIXED_KEYS); } else if (PX_EC_ALG == e_brainpool_p256_r1) { v_enc_signed_ec_signature := f_encryptWithEciesBrainpoolp256WithSha256(bit2oct(encvalue(v_signed_at_signature)), v_public_enc_key, v_compressed_mode, ''O, v_public_compressed_ephemeral_key, v_public_compressed_ephemeral_mode, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce, PICS_SEC_FIXED_KEYS); } else { log("f_generate_inner_at_request: Wrong encryption variant"); return false; } 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; } v_recipientId := p_ea_hashed_id8; // RecipientId is the HashedId8 of the EA certificate log("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)); } p_inner_at_request.ecSignature := valueof( m_ec_signature( m_etsiTs103097Data_encrypted( m_encryptedData( { m_recipientInfo_signedDataRecipInfo( m_pKRecipientInfo( v_recipientId, v_encrypted_data_encryption_key )) }, m_SymmetricCiphertext_aes128ccm( 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 (p_compressed_key_mode == 0) { v_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_0(v_public_key_x); } else { v_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_1(v_public_key_x); } 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); } p_inner_at_request.publicKeys := valueof( // The freshly generated public keys to be used for the requested AT certificate m_publicKeys( m_publicVerificationKey_ecdsaNistP256( v_eccP256_curve_point ), m_encryptionKey( // FIXME Encryption keys could be optional -, m_publicEncryptionKey_ecdsaNistP256(v_enc_eccP256_curve_point) ) ) ); p_inner_at_request.hmacKey := v_hmac_key; log("p_inner_at_request= ", p_inner_at_request); return true; } // End of function f_generate_inner_at_request 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 authorization_validation_xxx { } // End of group authorization_validation_xxx group awaiting_messages { function f_http_send( in HeaderLines p_headers, in template (value) HttpMessage p_http_message ) runs on ItsPkiHttp { 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_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 { log("f_http_send: Invalid header value: ", v_content_text); } } } // End of function f_http_send 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 ) runs on ItsPkiHttp return boolean { var HeaderLines v_headers; var Oct32 v_request_hash; var Oct16 v_encrypted_sym_key; var Oct16 v_aes_sym_key; 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"); 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); 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 { [not(PICS_MULTIPLE_END_POINT)] httpPort.receive( mw_http_response( mw_http_response_ok( mw_http_message_body_binary( mw_binary_body_ieee1609dot2_data( mw_enrolmentResponseMessage( mw_encryptedData( -, mw_SymmetricCiphertext_aes128ccm ))))))) -> value 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, false, v_etsi_ts_102941_data) == false) { log("f_await_http_inner_ec_request_response: Failed to verify PKI message ***"); } else { 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(substr(v_request_hash, 0, 16), mw_etsiTs103097Certificate(-, mw_toBeSignedCertificate_ec, -))))) { p_inner_ec_response := v_etsi_ts_102941_data.content.enrolmentResponse; if (f_verify_ec_certificate(v_etsi_ts_102941_data.content.enrolmentResponse.certificate, vc_eaCertificate, p_compressed_public_key, p_compressed_mode)) { log("f_await_http_inner_ec_request_response: Well-secured EA certificate received ***"); log("p_inner_ec_response= ", p_inner_ec_response); return true; } else { log("f_await_http_inner_ec_request_response: Cannot verify EC certificate signature ***"); return true; // For debug mode only } } else { log("f_await_http_inner_ec_request_response: Unexpected message received ***"); } } } [PICS_MULTIPLE_END_POINT] httpEcPort.receive( mw_http_response( mw_http_response_ok( mw_http_message_body_binary( mw_binary_body_ieee1609dot2_data( mw_enrolmentResponseMessage( mw_encryptedData( -, mw_SymmetricCiphertext_aes128ccm ))))))) -> value 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, false, v_etsi_ts_102941_data) == false) { log("f_await_http_inner_ec_request_response: Failed to verify PKI message ***"); } else { 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(substr(v_request_hash, 0, 16), mw_etsiTs103097Certificate(-, mw_toBeSignedCertificate_ec, -))))) { p_inner_ec_response := v_etsi_ts_102941_data.content.enrolmentResponse; if (f_verify_ec_certificate(v_etsi_ts_102941_data.content.enrolmentResponse.certificate, vc_eaCertificate, p_compressed_public_key, p_compressed_mode)) { log("f_await_http_inner_ec_request_response: Well-secured EA certificate received ***"); log("p_inner_ec_response= ", p_inner_ec_response); return true; } else { log("f_await_http_inner_ec_request_response: Cannot verify EC certificate signature ***"); return true; // For debug mode only } } else { log("f_await_http_inner_ec_request_response: Unexpected message received ***"); } } } [] tc_ac.timeout { log("f_await_http_inner_ec_request_response: Expected message not received ***"); } } // End of 'alt' statement return false; } // End of function f_await_http_inner_ec_request_response } // 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, 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"); // Signed the encoded PKI message v_tbs := m_toBeSignedData( m_signedDataPayload( m_etsiTs103097Data_unsecured(p_pki_message) ), m_headerInfo_inner_pki_request(-, f_getCurrentTimeUtc()) ); log("f_build_pki_secured_request_message_signed_with_pop: signer: ", p_signer_identifier); if (PICS_SECPKI_REENROLMENT == false) { // This is the first enrolment, we used Factory keys //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; 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)), PX_EC_HASH, p_private_key); } // Add the signature and create EtsiTs103097Data-Signed data structure 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)); // Encrypt encode EtsiTs103097Data-Signed data structure if (PICS_SEC_FIXED_KEYS) { p_salt := '77C0637C3558B3238FDE1EEC376DA080BE4076FB8491CA0F8C19FD34DF298CEB'O; } if (PX_EC_ALG == 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, PICS_SEC_FIXED_KEYS); } else if (PX_EC_ALG == e_brainpool_p256_r1) { v_encrypted_request := f_encryptWithEciesBrainpoolp256WithSha256(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, PICS_SEC_FIXED_KEYS); } 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 (PX_EC_ALG == 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 (PX_EC_ALG == 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( 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); if (PICS_SEC_FIXED_KEYS) { p_request_hash := '10ED97A2F2933DD3AC55F47022D125E18F5E1AA024613E616A75BA4979EFE318'O; } else { 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, 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 (PICS_SEC_FIXED_KEYS) { p_salt := '77C0637C3558B3238FDE1EEC376DA080BE4076FB8491CA0F8C19FD34DF298CEB'O; } if (PX_EC_ALG == 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, PICS_SEC_FIXED_KEYS); } else if (PX_EC_ALG == e_brainpool_p256_r1) { v_encrypted_request := f_encryptWithEciesBrainpoolp256WithSha256(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, PICS_SEC_FIXED_KEYS); } 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 (PX_EC_ALG == 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 (PX_EC_ALG == 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( 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); if (PICS_SEC_FIXED_KEYS) { p_request_hash := '10ED97A2F2933DD3AC55F47022D125E18F5E1AA024613E616A75BA4979EFE318'O; } else { 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, 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"); // 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 (PICS_SEC_FIXED_KEYS) { p_salt := '77C0637C3558B3238FDE1EEC376DA080BE4076FB8491CA0F8C19FD34DF298CEB'O; } if (PX_EC_ALG == 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, PICS_SEC_FIXED_KEYS); } else if (PX_EC_ALG == e_brainpool_p256_r1) { v_encrypted_request := f_encryptWithEciesBrainpoolp256WithSha256(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, PICS_SEC_FIXED_KEYS); } 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 (PX_EC_ALG == 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 (PX_EC_ALG == 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( 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); if (PICS_SEC_FIXED_KEYS) { p_request_hash := '10ED97A2F2933DD3AC55F47022D125E18F5E1AA024613E616A75BA4979EFE318'O; } else { 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_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_getCurrentTimeUtc()) ); 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 octetstring 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( 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; 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); // 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: v_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, mw_ieee1609Dot2_headerInfo(c_its_aid_SCR) ) ) ))); 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)); if (f_getCertificateFromDigest(f_HashedId8FromSha256(p_issuer), v_certificate) == 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 /** * @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_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, 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 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); // 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) == 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. 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 /** * @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 octetstring p_public_key_compressed, in integer p_compressed_mode ) return boolean { var bitstring v_encoded_cert; var Oct32 v_ec_cert_hash; var HashedId8 v_ec_cert_hashed_id8; // 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); v_ec_cert_hashed_id8 := f_HashedId8FromSha256(v_ec_cert_hash); log("f_verify_ec_certificate: ==> EC certificate HashedId8: ", v_ec_cert_hashed_id8); // Check the signer log("f_verify_ec_certificate: ", match(p_ec_certificate.issuer, mw_issuerIdentifier_sha256AndDigest)); if (match(p_ec_certificate.issuer, mw_issuerIdentifier_sha256AndDigest)) { return false; } // Check EC certificate signature // TODO Who sign the EC certificate? 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 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 // TODO Who sign the EC certificate? if (f_verifyCertificateSignatureWithPublicKey(p_at_certificate, p_aa_certificate.toBeSigned.verifyKeyIndicator.verificationKey) == false) { log("f_verify_at_certificate: Signature not verified"); return false; } return true; } // End of function f_verify_at_certificate } // End of group inner_ec_xxx group security_function { // TODO To be moved in LibItsSecurity_Function module function f_extract_enc_key( in Certificate p_certificate, out octetstring p_public_enc_key, out integer p_compressed_enc_key_mode ) return boolean { log(">>> f_extract_enc_key: ", p_certificate); if (ischosen(p_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256)) { if (ischosen(p_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_0)) { p_public_enc_key := p_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_0; p_compressed_enc_key_mode := 0; } else if (ischosen(p_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_1)) { p_public_enc_key := p_certificate.toBeSigned.encryptionKey.publicKey.eciesNistP256.compressed_y_1; p_compressed_enc_key_mode := 1; } else { log("f_extract_enc_key: Non canonical certificate: ", p_certificate); return false; } } else if (ischosen(p_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1)) { if (ischosen(p_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_0)) { p_public_enc_key := p_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_0; p_compressed_enc_key_mode := 0; } else if (ischosen(p_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_1)) { p_public_enc_key := p_certificate.toBeSigned.encryptionKey.publicKey.eciesBrainpoolP256r1.compressed_y_1; p_compressed_enc_key_mode := 0; } else { log("f_extract_enc_key: Non canonical certificate: ", p_certificate); return false; } } else { log("f_extract_enc_key: Invalid certificate: ", p_certificate); return false; } return true; } // End of function f_extract_enc_key } // End of group security_function 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_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_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_avt_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_avt_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_avt_http_response_from_iut } // End of group altsteps } // End of module LibItsPki_Functions