/** * @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_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_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 { /** * @desc Setups default configuration * @param p_certificateId 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 */ { map(self:httpPort, system:httpPort); 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_readCertificate(p_aa_certificate_id, vc_ecCertificate); // TODO To be removed // f_readSigningKey(p_aa_certificate_id, vc_ecPrivateKey); // TODO To be removed // f_readEncryptingKey(p_ea_certificate_id, vc_eaPrivateEncKey); // TODO To be removed f_getCertificateDigest(p_ea_certificate_id, vc_eaHashedId8); f_getCertificateHash(p_ea_certificate_id, 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("vc_aaHashedId8= ", vc_aaHashedId8); log("vc_aaWholeHash= ", vc_aaWholeHash); // f_readCertificate(p_peerCertificateId, vc_peerEaCertificate); // TODO To be removed // f_getCertificateHash(p_peerCertificateId, vc_eaPeerWholeHash); // TODO To be removed activate(a_default_pki_http()); } // End of function f_cfHttpUp function f_cfUp_itss( in charstring p_certificateId := "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_cfHttpDown() runs on ItsPkiHttp /* TITAN TODO: system ItsPkiHttpSystem */ { unmap(self:httpPort, system:httpPort); 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_certificateId := "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_certificateId, 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 := f_setupIutCertificate(vc_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_sendUtTriggerPrimitive( in charstring p_cannonicalId, in Oct1 p_encAlgorithm, in octetstring p_private_key, in octetstring p_publicKeyCompressed, in integer p_compressedMode ) runs on ItsPkiItss { var TriggerEnrolmentRequest v_ut_trigger_enrolment_request; var octetstring v_compressed_public_key; if (p_compressedMode == 2) { // TODO v_compressed_public_key := int2oct(p_compressedMode, 1) & p_publicKeyCompressed? v_compressed_public_key := '02'O & p_publicKeyCompressed; } else { v_compressed_public_key := '03'O & p_publicKeyCompressed; } v_ut_trigger_enrolment_request := { p_cannonicalId, p_encAlgorithm, 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_sendUtTriggerPrimitive: 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_sendUtTriggerPrimitive } // End of group ut_port group http { // TODO Split into EinnerEc, Authorization & AuthorizationValidation function f_http_build_inner_ec_request( // TODO Cleanup parameters out octetstring p_private_key, out octetstring p_publicKeyCompressed, out integer p_compressedMode, 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_publicKeyCompressed, p_compressedMode, v_inner_ec_request) == false) { log("*** f_http_build_inner_ec_request: ERROR: Failed to generate InnerEcRequest ***"); f_selfOrClientSyncAndVerdict("error", e_error); } // 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("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); log("*** f_http_build_inner_ec_request: First enrolment: ", PX_FIRST_ENROLMENT); p_salt := vc_eaWholeHash; if (PX_FIRST_ENROLMENT == true) { // This is the first enrolment, we used Factory keys v_ret_code := f_build_pki_secured_request_message(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 var Oct32 v_ec_private_key; var HashedId8 v_ec_hashed_id8; // Retrieve EC certificate from the first enrolment // TODO Set v_ec_private_key & v_ec_hashed_id8 v_ret_code := f_build_pki_secured_request_message(v_ec_private_key, valueof(m_signerIdentifier_digest(v_ec_hashed_id8)), v_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_inner_ec_request: ERROR: Failed to generate InnerEcRequestSignedForPop ***"); f_selfOrClientSyncAndVerdict("error", e_error); } log("*** f_http_build_inner_ec_request: DEBUG: p_ieee1609dot2_signed_and_encrypted_data= ", p_ieee1609dot2_signed_and_encrypted_data); log("*** f_http_build_inner_ec_request: DEBUG: 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_publicKeyCompressed, out integer p_compressedMode, 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_publicKeyCompressed, p_compressedMode, v_inner_ec_request) == false) { log("*** f_http_build_invalid_enrolment_request: ERROR: Failed to generate InnerEcRequest ***"); f_selfOrClientSyncAndVerdict("error", e_error); } // 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("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_inner_ec_request: ERROR: Non canonical EA certificate ***"); f_selfOrClientSyncAndVerdict("error", e_error); } log("*** f_http_build_inner_ec_request: Public encryption key: ", v_public_enc_key); log("*** f_http_build_inner_ec_request: Public encryption key comp: ", v_compressed_enc_key_mode); p_salt := vc_eaWholeHash; if (PX_FIRST_ENROLMENT == true) { // This is the first enrolment, we used Factory keys v_ret_code := f_build_pki_secured_request_message(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 var Oct32 v_ec_private_key; var HashedId8 v_ec_hashed_id8; // Retrieve EC certificate from the first enrolment // TODO Set v_ec_private_key & v_ec_hashed_id8 v_ret_code := f_build_pki_secured_request_message(v_ec_private_key, valueof(m_signerIdentifier_digest(v_ec_hashed_id8)), v_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); return; } 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_authorization_request( in Certificate p_ec_certificate, // Enrolment credentials certificate in octetstring p_ec_private_key, out octetstring p_private_key, out octetstring p_publicKeyCompressed, out integer p_compressedMode, out octetstring p_private_enc_key, out octetstring p_publicEncKeyCompressed, out integer p_compressedEncMode, 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 verification keys for the certificate to be requested if (f_generate_key_pair_nistp256(p_private_key, v_public_key_x, v_public_key_y, p_publicKeyCompressed, p_compressedMode) == false) { log("*** f_http_build_authorization_request: ERROR: Failed to generate verification key ***"); f_selfOrClientSyncAndVerdict("error", e_error); return; } // Generate encryption keys for the certificate to be requested if (PX_INCLUDE_ENCRYPTION_KEYS) { if (f_generate_key_pair_nistp256(p_private_enc_key, v_public_enc_key_x, v_public_enc_key_y, p_publicEncKeyCompressed, p_compressedEncMode) == false) { log("*** f_http_build_authorization_request: ERROR: Failed to generate encryption key ***"); f_selfOrClientSyncAndVerdict("error", e_error); return; } } if (f_generate_inner_at_request(vc_eaCertificate, vc_eaHashedId8, p_ec_certificate, p_ec_private_key, p_private_key, v_public_key_x, v_public_key_y, p_compressedMode, p_private_enc_key, v_public_enc_key_x, v_public_enc_key_y, p_compressedEncMode, v_inner_at_request) == false) { log("*** f_http_build_authorization_request: ERROR: Failed to generate AuthorizationValidationRequest ***"); f_selfOrClientSyncAndVerdict("error", e_error); return; } log("v_inner_at_request= ", v_inner_at_request); if (PX_AUTHORIZATION_REQUEST_WITH_POP) { // TODO Set Ieee1609Dot2Data p_inner_at_request_data } // else TODO Check what to do // Secure InnerAtRequest message if (f_extract_enc_key(vc_aaCertificate, v_public_enc_key, v_compressed_enc_key_mode) == false) { log("*** f_http_build_inner_ec_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); log("*** f_http_build_authorization_request: First enrolment: ", PX_FIRST_ENROLMENT); p_salt := vc_aaWholeHash; log("*** f_http_build_authorization_request: p_salt: ", p_salt); if(f_build_pki_secured_request_message(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); } 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( out octetstring p_private_key, out octetstring p_publicKeyCompressed, out integer p_compressedMode, out Ieee1609Dot2Data p_ieee1609dot2_signed_and_encrypted_data ) 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; /* TODO if (f_generate_authorization_validation_request(vc_eaCertificate, vc_eaHashedId8, p_private_key, p_publicKeyCompressed, p_compressedMode, v_authorization_validation_request) == false) { log("*** f_http_build_authorization_validation_request: ERROR: Failed to generate AuthorizationValidationRequest ***"); f_selfOrClientSyncAndVerdict("error", e_error); }*/ // 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_inner_ec_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); /** TODO: Load certificate according to the IUT role ==> a complete fucntion which set up the TestSustem certificate,keyy... according to the IUT role **/ log("*** f_http_build_inner_ec_request: ERROR: Need to add TestSystem variable vc_aa ***"); f_selfOrClientSyncAndVerdict("error", e_error); /* if (f_build_pki_secured_request_message(vc_aaPrivateKey, valueof(m_signerIdentifier_digest(vc_aaHashedId8)), vc_eaHashedId8/\*recipientId*\/, v_public_enc_key, v_compressed_enc_key_mode, vc_eaWholeHash, bit2oct(encvalue(m_etsiTs102941Data_authorization_validation_request(v_authorization_validation_request))), p_ieee1609dot2_signed_and_encrypted_data, p_request_hash) == false) { */ /* log("*** f_http_build_authorization_validation_request: ERROR: Failed to generate InnerEcRequestSignedForPop ***"); */ /* 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); } // End of function f_http_build_authorization_validation_request } // End of group http group generate_certificates { function f_generate_ec_certificate( in octetstring p_private_key, in InnerEcRequest p_inner_ec_request, out Certificate p_ec_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; v_cert := m_etsiTs103097Certificate( m_issuerIdentifier_sha256AndDigest(f_HashedId8FromSha256(f_hashWithSha256('616263'O))), m_toBeSignedCertificate_at( v_appPermissions, m_verificationKeyIndicator_verificationKey( m_publicVerificationKey_ecdsaNistP256( p_inner_ec_request.publicKeys.verificationKey.ecdsaNistP256 )), m_validityPeriod( 17469212, m_duration_years(10) ), 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 using ECDSA/SHA-256 (NIST p-256) v_sig := f_signWithEcdsaNistp256WithSha256(bit2oct(v_tbs), int2oct(11, 32), p_private_key); v_cert.signature_ := m_signature_ecdsaNistP256( m_ecdsaP256Signature( m_eccP256CurvePoint_x_only( substr(v_sig, 0, 32) ), substr(v_sig, 32, 32) ) ); log("v_cert= ", v_cert); p_ec_certificate := valueof(v_cert); return true; } // End of function f_generate_ec_certificate 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; v_cert := m_etsiTs103097Certificate( m_issuerIdentifier_sha256AndDigest(f_HashedId8FromSha256(f_hashWithSha256('616263'O))), m_toBeSignedCertificate_at( v_appPermissions, m_verificationKeyIndicator_verificationKey( m_publicVerificationKey_ecdsaNistP256( p_inner_ec_request.publicKeys.verificationKey.ecdsaNistP256 )), m_validityPeriod( 17469212, m_duration_years(10) ), 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 using ECDSA/SHA-256 (NIST p-256) v_sig := f_signWithEcdsaNistp256WithSha256(bit2oct(v_tbs), int2oct(11, 32), p_private_key); v_cert.signature_ := m_signature_ecdsaNistP256( m_ecdsaP256Signature( m_eccP256CurvePoint_x_only( substr(v_sig, 0, 32) ), substr(v_sig, 32, 32) ) ); 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_publicKeyCompressed, out integer p_compressedMode, 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_nistp256(p_private_key, v_publicKeyX, v_publicKeyY, p_publicKeyCompressed, p_compressedMode) == false) { log ("f_generate_inner_ec_request: failed to generate keys"); return false; } if (p_compressedMode == 0) { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(p_publicKeyCompressed)); } else { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(p_publicKeyCompressed)); } log ("f_generate_inner_ec_request: ", v_eccP256_curve_point); // 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(623, { 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 ) ) ); 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; // 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_ec_request( c_its_aid_SCR, f_getCurrentTimeUtc() ) ); // Signed the encoded InnerEcRequestSignedForPop v_tbs_signed := f_signWithEcdsaNistp256WithSha256(bit2oct(encvalue(v_tbs)), int2oct(0, 32), p_private_key); // Finalyse signed InnerEcRequestSignedForPop p_inner_ec_request_signed_for_pop := valueof( m_etsiTs103097Data_signed( m_signedData( sha256, v_tbs, m_signerIdentifier_self, m_signature_ecdsaNistP256( m_ecdsaP256Signature( m_eccP256CurvePoint_x_only( substr(v_tbs_signed, 0, 32) ), substr(v_tbs_signed, 32, 32) ) ) ) ) ); return true; } // End of function f_generate_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, in octetstring p_private_key, in octetstring p_public_key_x, in octetstring p_public_key_y, in integer p_compressed_key_mode, in octetstring p_private_enc_key, in octetstring p_public_enc_key_x, in octetstring p_public_enc_key_y, in integer p_compressed_enc_key_mode, out InnerAtRequest p_inner_at_request ) return boolean { // Local variables 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_ec_signature; var template (value) EccP256CurvePoint v_eccP256_curve_point; var template (value) EccP256CurvePoint v_enc_eccP256_curve_point; var HashAlgorithm v_hashId; // 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("v_ec_hash= ", v_ec_hash); // Generate 32 octets length secret key v_hmac_key := f_hashWithSha256(int2oct(f_getCurrentTime(), 12)); log("v_hmac_key= ", v_hmac_key); // Generate tag based on the concatenation of verification keys & encryption keys v_message_to_tag := p_public_key_x & p_public_key_y & p_public_enc_key_x & p_public_enc_key_y; log("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("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, { { subjectPermissions := { all_ := NULL }, minChainLength := 1, chainLengthRange := 0, eeType := '00000000'B } }, 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("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_ec_request( // HeaderInfo c_its_aid_SCR, f_getCurrentTimeUtc()) ); log("v_tbs= ", v_tbs); // Signed ToBeSigned payload using the private key of EC certificate obtained from Enrolment request v_tbs_signed := f_signWithEcdsaNistp256WithSha256(bit2oct(encvalue(v_tbs)), v_ec_hash, p_ec_private_key); // In case of ITS-S privacy, v_signed_ec_signature contained the data to be encrypted if (ischosen(p_ec_certificate.signature_.ecdsaBrainpoolP384r1Signature)) { v_hashId := sha384; } else { v_hashId := sha256; } v_signed_ec_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 m_signature_ecdsaNistP256( m_ecdsaP256Signature( m_eccP256CurvePoint_x_only( substr(v_tbs_signed, 0, 32) ), substr(v_tbs_signed, 32, 32) ) ) ) ) ); log("v_signed_ec_signature= ", v_signed_ec_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_publicEphemeralKeyCompressed; var integer v_ephemeralKeyModeCompressed; var octetstring v_enc_signed_ec_signature; // Use EA certificate for the encryption 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 { return false; } v_enc_signed_ec_signature := f_encryptWithEciesNistp256WithSha256(bit2oct(encvalue(v_signed_ec_signature)), v_public_enc_key, v_compressed_mode, ''O, v_publicEphemeralKeyCompressed, v_ephemeralKeyModeCompressed, v_aes_sym_key, v_encrypted_sym_key, v_authentication_vector, v_nonce, PICS_SEC_FIXED_KEYS); 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_ephemeralKeyModeCompressed == 0) { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_publicEphemeralKeyCompressed)); } else { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_publicEphemeralKeyCompressed)); } p_inner_at_request.ecSignature := valueof( m_ec_signature( m_etsiTs103097Data_encrypted( m_encryptedData( { m_recipientInfo_signedDataRecipInfo( m_pKRecipientInfo( v_recipientId, m_encryptedDataEncryptionKey_eciesNistP256( m_evciesP256EncryptedKey( v_eccP256_curve_point, v_encrypted_sym_key, v_authentication_vector )))) }, 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_ec_signature)); } // Build the InnerAtRequest, EcSignature field is already set if (p_compressed_key_mode == 0) { v_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_0(p_public_key_x); } else { v_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_1(p_public_key_x); } if (p_compressed_enc_key_mode == 0) { v_enc_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_0(p_public_enc_key_x); } else { v_enc_eccP256_curve_point := m_eccP256CurvePoint_compressed_y_1(p_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_xxx { } // End of group authorization_xxx group authorization_validation_xxx { } // End of group authorization_validation_xxx 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_publicKeyCompressed The public compressed key (canonical form) for encryption * @param p_compressedMode 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 octetstring p_private_key, in SignerIdentifier p_signer_identifier, in HashedId8 p_recipientId, in octetstring p_publicKeyCompressed, in integer p_compressedMode, 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 template (value) Ieee1609Dot2Data v_ieee1609dot2_signed_data; var octetstring v_encoded_inner_ec_request; var HashedId8 v_recipientId; var octetstring v_publicEphemeralKeyCompressed; var integer v_ephemeralKeyModeCompressed; var octetstring v_encrypted_inner_ec_request; // Signed the encoded PKI message v_tbs := m_toBeSignedData( m_signedDataPayload( m_etsiTs103097Data_unsecured(p_pki_message) ), m_headerInfo_inner_ec_request(c_its_aid_SCR, 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_request := bit2oct(encvalue(v_ieee1609dot2_signed_data)); // Calculate the SHA256 of v_encoded_inner_ec_request if (PICS_SEC_FIXED_KEYS) { p_request_hash := '10ED97A2F2933DD3AC55F47022D125E18F5E1AA024613E616A75BA4979EFE318'O; } else { p_request_hash := f_hashWithSha256(v_encoded_inner_ec_request); log("p_request_hash= ", p_request_hash); } // Encrypt encode EtsiTs103097Data-Signed data structure if (PICS_SEC_FIXED_KEYS) { p_salt := '77C0637C3558B3238FDE1EEC376DA080BE4076FB8491CA0F8C19FD34DF298CEB'O; } v_encrypted_inner_ec_request := f_encryptWithEciesNistp256WithSha256(v_encoded_inner_ec_request, p_publicKeyCompressed, p_compressedMode, p_salt, v_publicEphemeralKeyCompressed, v_ephemeralKeyModeCompressed, p_aes_sym_key, p_encrypted_sym_key, p_authentication_vector, p_nonce, PICS_SEC_FIXED_KEYS); log("p_aes_sym_key= ", p_aes_sym_key); log("p_encrypted_sym_key= ", p_encrypted_sym_key); log("p_authentication_vector= ", p_authentication_vector); log("p_nonce= ", p_nonce); log("p_recipientId= ", p_recipientId); if (p_recipientId == int2oct(0, 8)) { log("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("v_recipientId= ", v_recipientId); // Fill Certificate template with the public compressed keys (canonical form) if (v_ephemeralKeyModeCompressed == 0) { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_0(v_publicEphemeralKeyCompressed)); } else { v_eccP256_curve_point := valueof(m_eccP256CurvePoint_compressed_y_1(v_publicEphemeralKeyCompressed)); } p_ieee1609dot2_signed_and_encrypted_data := valueof( m_etsiTs103097Data_encrypted( m_encryptedData( { m_recipientInfo_signedDataRecipInfo( m_pKRecipientInfo( v_recipientId, m_encryptedDataEncryptionKey_eciesNistP256( m_evciesP256EncryptedKey( v_eccP256_curve_point, p_encrypted_sym_key, p_authentication_vector )))) }, m_SymmetricCiphertext_aes128ccm( m_aesCcmCiphertext( p_nonce, v_encrypted_inner_ec_request ) ) ) ) ); return true; } // End of function f_build_pki_secured_request_message /** * @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_publicKeyCompressed The public compressed key (canonical form) for encryption * @param p_compressedMode 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_ec_response(c_its_aid_SCR, 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 ) ) ) ) ); 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_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_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 Certificate p_certificate, // TODO Tobe removed 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_message: p_private_enc_key= ", p_private_enc_key); log(">>> f_verify_pki_message: p_aes_sym_key= ", p_aes_sym_key); log(">>> f_verify_pki_message: p_authentication_vector= ", p_authentication_vector); log(">>> f_verify_pki_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("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("v_ieee1609dot2_signed_data= ", v_ieee1609dot2_signed_data); // 3. Check the signature log("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; } } //log("v_certificate= ", v_certificate); if (ischosen(v_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.compressed_y_0)) { v_ret := f_verifyWithEcdsaNistp256WithSha256( bit2oct(v_tbs), p_issuer, v_ieee1609dot2_signed_data.content.signedData.signature_.ecdsaNistP256Signature.rSig.x_only & v_ieee1609dot2_signed_data.content.signedData.signature_.ecdsaNistP256Signature.sSig, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.compressed_y_0, 0); } else { v_ret := f_verifyWithEcdsaNistp256WithSha256( bit2oct(v_tbs), p_issuer, v_ieee1609dot2_signed_data.content.signedData.signature_.ecdsaNistP256Signature.rSig.x_only & v_ieee1609dot2_signed_data.content.signedData.signature_.ecdsaNistP256Signature.sSig, v_certificate.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.compressed_y_1, 1); } if (v_ret == false) { if (p_check_security == true) { return false; } } // 4. Return the PKI message log("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) { if (p_check_security == true) { return false; } } return true; } // End of function f_verify_pki_message /** * @desc Verify the generated EA certificate * @param p_ea_certificate The new EA certificate * @param p_publicKeyCompressed The public compressed key (canonical form) for signature check * @param p_compressedMode The public compressed key mode * @return true on success, false otherwise */ function f_verify_ea_certificate( in Certificate p_ea_certificate, in octetstring p_publicKeyCompressed, in integer p_compressedMode ) return boolean { var bitstring v_encoded_tbs; var boolean v_result; // Check certificate format v_result := match(p_ea_certificate, mw_etsiTs103097Certificate(mw_issuerIdentifier_self, mw_toBeSignedCertificate_ea, -)); // Check the signer // Check EA certificate signature v_encoded_tbs := encvalue(p_ea_certificate.toBeSigned); v_result := v_result and f_verifyWithEcdsaNistp256WithSha256( bit2oct(v_encoded_tbs), int2oct(0, 32), // self p_ea_certificate.signature_.ecdsaNistP256Signature.rSig.x_only & p_ea_certificate.signature_.ecdsaNistP256Signature.sSig, p_publicKeyCompressed, p_compressedMode); return v_result; } // End of function f_verify_ea_certificate /** * @desc Verify the generated AA certificate * @param p_aa_certificate The new EA certificate * @param p_publicKeyCompressed The public compressed key (canonical form) for signature check * @param p_compressedMode The public compressed key mode * @return true on success, false otherwise */ function f_verify_aa_certificate( in Certificate p_aa_certificate, in octetstring p_publicKeyCompressed, in integer p_compressedMode ) return boolean { var bitstring v_encoded_tbs; var boolean v_result; // Check certificate format v_result := match(p_aa_certificate, mw_etsiTs103097Certificate(mw_issuerIdentifier_self, mw_toBeSignedCertificate_aa, -)); // Check the signer // Check EA certificate signature v_encoded_tbs := encvalue(p_aa_certificate.toBeSigned); v_result := v_result and f_verifyWithEcdsaNistp256WithSha256( bit2oct(v_encoded_tbs), int2oct(0, 32), // self p_aa_certificate.signature_.ecdsaNistP256Signature.rSig.x_only & p_aa_certificate.signature_.ecdsaNistP256Signature.sSig, p_publicKeyCompressed, p_compressedMode); return v_result; } // End of function f_verify_aa_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 altstes { altstep a_default_pki_http() runs on ItsPkiHttp { [] httpPort.receive( mw_http_response( mw_http_response_ko )) { tc_ac.stop; log("*** a_default: ERROR: HTTP Server error ***"); f_selfOrClientSyncAndVerdict("error", e_error); } [] httpPort.receive(mw_http_request) { tc_ac.stop; log("*** a_default: ERROR: Unexpected HTTP Request received ***"); f_selfOrClientSyncAndVerdict("error", e_error); } [] httpPort.receive(mw_http_response) { tc_ac.stop; log("*** a_default: ERROR: Unexpected HTTP Response received ***"); f_selfOrClientSyncAndVerdict("error", e_error); } [] httpPort.receive { tc_ac.stop; log("*** a_default: ERROR: Unexpected HTTP message received ***"); f_selfOrClientSyncAndVerdict("error", e_error); } } } } // End of module LibItsPki_Functions