module TestCodec_ChainOfCertificates {
  
  // LibCommon
  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 EtsiTs103097Module language "ASN.1:1997" all;
  
  // LibItsGeoNetworking
  import from LibItsGeoNetworking_EncdecDeclarations all;
  import from LibItsGeoNetworking_TypesAndValues all;
  import from LibItsGeoNetworking_Templates all;
    
  // LibItsSecurity
  import from LibItsSecurity_EncdecDeclarations all;
  import from LibItsSecurity_TypesAndValues all;
  import from LibItsSecurity_Templates all;
  import from LibItsSecurity_Functions all;
  import from LibItsSecurity_Pixits all;
  
  // TestCodec
  import from TestCodec_TestAndSystem all;
  
  type record sec_info {
    EtsiTs103097Certificate   cert,
    octetstring               enc_cert,
    Oct32                     private_key,
    Oct32                     public_key_x,
    Oct32                     public_key_y,
    HashedId8                 hashid8,
    HashedId8                 issuer
  }
      
  type record chain_sec_info {
    sec_info ca,
    sec_info aa,
    sec_info at
  }

  testcase tc_full_check_certificate_1() runs on TCType system TCType {
    var chain_sec_info v_chain_sec_info;
    var bitstring v_enc_msg := ''B;
    var template (value) GnNonSecuredPacket v_gnNonSecuredPacket;
    var template (value) EtsiTs103097Data v_secured_data;
    var template (value) GeoNetworkingPdu v_gnSecuredPacket;
    
    // Generate CA certificate
    v_chain_sec_info.ca.cert := f_create_ca_certificate_nistP256_1(v_chain_sec_info.ca);
    v_enc_msg := encvalue(v_chain_sec_info.ca.cert);
    v_chain_sec_info.ca.enc_cert := bit2oct(v_enc_msg);
    v_chain_sec_info.ca.hashid8 := f_HashedId8FromSha256(v_chain_sec_info.ca.enc_cert);
    v_chain_sec_info.ca.issuer := v_chain_sec_info.ca.hashid8;
    // Verify signature of CA certificate by itself
    v_enc_msg := encvalue(v_chain_sec_info.ca.cert.toBeSigned);
    if (f_verifyWithEcdsaNistp256WithSha256(
                                            bit2oct(v_enc_msg), 
                                            v_chain_sec_info.ca.cert.signature_.ecdsaNistP256Signature.rSig.x_only & v_chain_sec_info.ca.cert.signature_.ecdsaNistP256Signature.sSig,
                                            v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.x,
                                            v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.y
                                           ) == false) {
      setverdict(fail);
    } else {
      setverdict(pass);
      v_enc_msg := encvalue(v_chain_sec_info.ca.cert);
      log("Root keys: ", v_chain_sec_info.ca.cert);
    }
    
    // Generate AA certificate
    v_chain_sec_info.aa.cert := f_create_aa_certificate_nistP256_1(v_chain_sec_info.ca, v_chain_sec_info.aa);
    v_enc_msg := encvalue(v_chain_sec_info.aa.cert);
    v_chain_sec_info.aa.enc_cert := bit2oct(v_enc_msg);
    v_chain_sec_info.aa.hashid8 := f_HashedId8FromSha256(v_chain_sec_info.aa.enc_cert);
    v_chain_sec_info.aa.issuer := v_chain_sec_info.ca.hashid8;
    // Verify signature of AA certificate by CA certificate
    v_enc_msg := encvalue(v_chain_sec_info.aa.cert.toBeSigned);
    if (f_verifyWithEcdsaNistp256WithSha256(
                                            bit2oct(v_enc_msg), 
                                            v_chain_sec_info.aa.cert.signature_.ecdsaNistP256Signature.rSig.x_only & v_chain_sec_info.aa.cert.signature_.ecdsaNistP256Signature.sSig,
                                            v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.x,
                                            v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.y
                                           ) == false) {
      setverdict(fail);
    } else {
      v_enc_msg := encvalue(v_chain_sec_info.aa.cert);
      log("AA keys: ", v_chain_sec_info.aa.cert);
      setverdict(pass)
    }

    // Generate AT certificate
    v_chain_sec_info.at.cert := f_create_at_certificate_nistP256_1(v_chain_sec_info.aa, v_chain_sec_info.at);
    v_enc_msg := encvalue(v_chain_sec_info.at.cert);
    v_chain_sec_info.at.enc_cert := bit2oct(v_enc_msg);
    v_chain_sec_info.at.hashid8 := f_HashedId8FromSha256(v_chain_sec_info.at.enc_cert);
    v_chain_sec_info.at.issuer := v_chain_sec_info.aa.hashid8;
    // Verify signature of AT certificate by AA certificate
    v_enc_msg := encvalue(v_chain_sec_info.at.cert.toBeSigned);
    if (f_verifyWithEcdsaNistp256WithSha256(
                                            bit2oct(v_enc_msg), 
                                            v_chain_sec_info.at.cert.signature_.ecdsaNistP256Signature.rSig.x_only & v_chain_sec_info.at.cert.signature_.ecdsaNistP256Signature.sSig,
                                            v_chain_sec_info.aa.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.x,
                                            v_chain_sec_info.aa.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.y
                                           ) == false) {
      setverdict(fail);
    } else {
      setverdict(pass);
      v_enc_msg := encvalue(v_chain_sec_info.at.cert);
      log("AT keys: ", v_chain_sec_info.at.cert);
    }

    log("tc_full_check_certificate_1: Final chain = ", v_chain_sec_info);
    
    // Store Private key in binary format
    fx_loadCertificates("/home/vagrant/tmp/Yann", "");
    fx_store_certificate("CERT_TEST_A_ROOT", v_chain_sec_info.ca.enc_cert, v_chain_sec_info.ca.private_key, v_chain_sec_info.ca.public_key_x, v_chain_sec_info.ca.public_key_y, v_chain_sec_info.ca.hashid8, v_chain_sec_info.ca.issuer);
    fx_store_certificate("CERT_TS_A_AA", v_chain_sec_info.aa.enc_cert, v_chain_sec_info.aa.private_key, v_chain_sec_info.aa.public_key_x, v_chain_sec_info.aa.public_key_y, v_chain_sec_info.aa.hashid8, v_chain_sec_info.aa.issuer);
    fx_store_certificate("CERT_TS_A_AT", v_chain_sec_info.at.enc_cert, v_chain_sec_info.at.private_key, v_chain_sec_info.at.public_key_x, v_chain_sec_info.at.public_key_y, v_chain_sec_info.at.hashid8, v_chain_sec_info.at.issuer);
    
    // Create a basic GeoNetworking message
  v_gnNonSecuredPacket := m_geoNwShbPacket(
                                           LongPosVector: {
                                           gnAddr := {
                                             typeOfAddress := e_manual,
                                             stationType := e_roadSideUnit,
                                             stationCountryCode := 33,
                                             mid := 'a4fedecabeef'O
                                           },
                                             timestamp_ := 123456,
                                             latitude := 4856,
                                             longitude := 675,
                                             pai := '1'B,
                                             speed := 55,
                                             heading := 9876
                                             }
                                           );
    // Build the secured message and sign it
  v_secured_data := f_build_and_sign_secured_message_nistP256_1(v_gnNonSecuredPacket, v_chain_sec_info.at);

    // Verify signature of secured messagee by AT certificate
    v_enc_msg := encvalue(v_secured_data.content.signedData.tbsData);
    if (f_verifyWithEcdsaNistp256WithSha256(
                                            bit2oct(v_enc_msg),
                                            valueof(v_secured_data.content.signedData.signature_.ecdsaNistP256Signature.rSig.x_only & v_secured_data.content.signedData.signature_.ecdsaNistP256Signature.sSig),
                                            v_chain_sec_info.at.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.x,
                                            v_chain_sec_info.at.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaNistP256.uncompressedP256.y
                                           ) == false) {
      setverdict(fail);
    } else {
      setverdict(pass)
    }

    // Finalyse the GeoNetworking message
    
    // TODO Create a chain of certificates
    
    // TODO Add encryption support
    
  } // End of testcase tc_full_check_certificate_1
  
  testcase tc_full_check_certificate_2() runs on TCType system TCType {
    var chain_sec_info v_chain_sec_info;
    var bitstring v_enc_msg := ''B;
    var template (value) GnNonSecuredPacket v_gnNonSecuredPacket;
    var template (value) EtsiTs103097Data v_secured_data;
    var template (value) GeoNetworkingPdu v_gnSecuredPacket;
    
    // Generate CA certificate
    v_chain_sec_info.ca.cert := f_create_ca_certificate_brainpoolP256_1(v_chain_sec_info.ca);
    v_enc_msg := encvalue(v_chain_sec_info.ca.cert);
    v_chain_sec_info.ca.enc_cert := bit2oct(v_enc_msg);
    v_chain_sec_info.ca.hashid8 := f_HashedId8FromSha256(f_hashWithSha256(bit2oct(v_enc_msg)));
    v_chain_sec_info.ca.issuer := v_chain_sec_info.ca.hashid8;
    // Verify signature of CA certificate by itself
    v_enc_msg := encvalue(v_chain_sec_info.ca.cert.toBeSigned);
    if (f_verifyWithEcdsaBrainpoolp256WithSha256(
                                                 bit2oct(v_enc_msg), 
                                                 v_chain_sec_info.ca.cert.signature_.ecdsaBrainpoolP256r1Signature.rSig.x_only & v_chain_sec_info.ca.cert.signature_.ecdsaBrainpoolP256r1Signature.sSig,
                                                 v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.x,
                                                 v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.y
                                                ) == false) {
      setverdict(fail);
    } else {
      setverdict(pass)
    }
    
    // Generate AA certificate
    v_chain_sec_info.aa.cert := f_create_aa_certificate_brainpoolP256_1(v_chain_sec_info.ca, v_chain_sec_info.aa);
    v_enc_msg := encvalue(v_chain_sec_info.aa.cert);
    v_chain_sec_info.aa.enc_cert := bit2oct(v_enc_msg);
    v_chain_sec_info.aa.hashid8 := f_HashedId8FromSha256(f_hashWithSha256(bit2oct(v_enc_msg)));
    v_chain_sec_info.aa.issuer := v_chain_sec_info.ca.hashid8;
    // Verify signature of AA certificate by CA certificate
    v_enc_msg := encvalue(v_chain_sec_info.aa.cert.toBeSigned);
    if (f_verifyWithEcdsaBrainpoolp256WithSha256(
                                                 bit2oct(v_enc_msg), 
                                                 v_chain_sec_info.aa.cert.signature_.ecdsaBrainpoolP256r1Signature.rSig.x_only & v_chain_sec_info.aa.cert.signature_.ecdsaBrainpoolP256r1Signature.sSig,
                                                 v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.x,
                                                 v_chain_sec_info.ca.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.y
                                                ) == false) {
      setverdict(fail);
    } else {
      setverdict(pass)
    }

    // Generate AT certificate
    v_chain_sec_info.at.cert := f_create_at_certificate_brainpoolP256_1(v_chain_sec_info.aa, v_chain_sec_info.at);
    v_enc_msg := encvalue(v_chain_sec_info.at.cert);
    v_chain_sec_info.at.enc_cert := bit2oct(v_enc_msg);
    v_chain_sec_info.at.hashid8 := f_HashedId8FromSha256(f_hashWithSha256(bit2oct(v_enc_msg)));
    v_chain_sec_info.at.issuer := v_chain_sec_info.aa.hashid8;
    // Verify signature of AT certificate by AA certificate
    v_enc_msg := encvalue(v_chain_sec_info.at.cert.toBeSigned);
    if (f_verifyWithEcdsaBrainpoolp256WithSha256(
                                                 bit2oct(v_enc_msg), 
                                                 v_chain_sec_info.at.cert.signature_.ecdsaBrainpoolP256r1Signature.rSig.x_only & v_chain_sec_info.at.cert.signature_.ecdsaBrainpoolP256r1Signature.sSig,
                                                 v_chain_sec_info.aa.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.x,
                                                 v_chain_sec_info.aa.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.y
                                                ) == false) {
      setverdict(fail);
    } else {
      setverdict(pass);
    }

    log("tc_full_check_certificate_2: Final chain = ", v_chain_sec_info);
    
    // Store Private key in binary format
    fx_loadCertificates("/home/vagrant/tmp/Yann", "");
    fx_store_certificate("CERT_TEST_B_ROOT", v_chain_sec_info.ca.enc_cert, v_chain_sec_info.ca.private_key, v_chain_sec_info.ca.public_key_x, v_chain_sec_info.ca.public_key_y, v_chain_sec_info.ca.hashid8, v_chain_sec_info.ca.issuer);
    fx_store_certificate("CERT_TS_B_AA", v_chain_sec_info.aa.enc_cert, v_chain_sec_info.aa.private_key, v_chain_sec_info.aa.public_key_x, v_chain_sec_info.aa.public_key_y, v_chain_sec_info.aa.hashid8, v_chain_sec_info.aa.issuer);
    fx_store_certificate("CERT_TS_B_AT", v_chain_sec_info.at.enc_cert, v_chain_sec_info.at.private_key, v_chain_sec_info.at.public_key_x, v_chain_sec_info.at.public_key_y, v_chain_sec_info.at.hashid8, v_chain_sec_info.at.issuer);
    
    // Create a basic GeoNetworking message
  v_gnNonSecuredPacket := m_geoNwShbPacket(
                                           LongPosVector: {
                                           gnAddr := {
                                             typeOfAddress := e_manual,
                                             stationType := e_roadSideUnit,
                                             stationCountryCode := 33,
                                             mid := 'a4fedecabeef'O
                                           },
                                             timestamp_ := 123456,
                                             latitude := 4856,
                                             longitude := 675,
                                             pai := '1'B,
                                             speed := 55,
                                             heading := 9876
                                             }
                                           );
    // Build the secured message and sign it
  v_secured_data := f_build_and_sign_secured_message_brainpoolP256_1(v_gnNonSecuredPacket, v_chain_sec_info.at);

    // Verify signature of secured messagee by AT certificate
  v_enc_msg := encvalue(v_secured_data.content.signedData.tbsData);
    if (f_verifyWithEcdsaBrainpoolp256WithSha256(
                                                 bit2oct(v_enc_msg),
                                                 valueof(v_secured_data.content.signedData.signature_.ecdsaNistP256Signature.rSig.x_only & v_secured_data.content.signedData.signature_.ecdsaNistP256Signature.sSig),
                                                 v_chain_sec_info.aa.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.x,
                                                 v_chain_sec_info.aa.cert.toBeSigned.verifyKeyIndicator.verificationKey.ecdsaBrainpoolP256r1.uncompressedP256.y
                                                 ) == false) {
      setverdict(fail);
    } else {
      setverdict(pass);
    }

    // Finalyse the GeoNetworking message
    
    // TODO Create a chain of certificates
    
    // TODO Add encryption support
  } // End of testcase tc_full_check_certificate_2
  
  /**
   * @desc Function to generate a CA certificate / NistP256
   * @see ETSI TS 103 097 V1.3.1 7.2.3 Root CA certificates
   */
  function f_create_ca_certificate_nistP256_1(
                                              out sec_info p_ca_sec_info
  ) runs on TCType return EtsiTs103097Certificate {
    var template (value) EtsiTs103097Certificate v_cert; // ETSI TS 103 097 V1.3.1 Clause 6 Bullet 1
    var charstring v_certId := "STF538 NistP256 Root Certificate";
    var HashAlgorithm v_self := sha256; // ETSI TS 103 097 V1.3.1 Clause 7.2.3 Root CA certificates Bullet 1
    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 })),
      valueof(m_appPermissions(38, { bitmapSsp := '830001'O }))
    };
    var SequenceOfPsidSspRange v_certIssuePermissions := { // ETSI TS 103 097 V1.3.1 Clause 7.2.3 Root CA certificates Bullet 3
      valueof(m_psidSspRange(1))
    };
    var HashedId8 v_sha256AndDigest;
    var Oct32 v_sig := int2oct(0, 32);
    var bitstring v_enc_msg := ''B;
      
    // Generate Private/Public keys
    f_generate_key_pair_nistp256(p_ca_sec_info.private_key, p_ca_sec_info.public_key_x, p_ca_sec_info.public_key_y);
    // Store Private key in binary format
    // Fill Certificate template with the public key
  v_cert := m_etsiTs103097Certificate(
                                      m_issuerIdentifier_self(v_self),
                                      m_toBeSignedCertificate_ca(
                                                              { name := v_certId },
                                                              v_appPermissions,
                                                              {
                                                                m_psidGroupPermissions(
                                                                                       m_subjectPermissions_explicit(
                                                                                                                     v_certIssuePermissions
                                                                                                                    ))
                                                                },
                                                              m_verificationKeyIndicator_verificationKey(
                                                                                                         m_publicVerificationKey_ecdsaNistP256(
                                                                                                                                               m_eccP256CurvePoint_uncompressed( // Signed by itself
                                                                                                                                                                                p_ca_sec_info.public_key_x,
                                                                                                                                                                                p_ca_sec_info.public_key_y
                                                                                                                                                                               ))),
                                                              m_validityPeriod(
                                                                               17469212,
                                                                               m_duration_years(10)
                                                                              )
                                                             )
                                      );
    // Encode it ==> Get octetstring
  v_enc_msg := encvalue(v_cert.toBeSigned);
    // Sign the certificate using ECDSA/SHA-256 (NIST p-256)
  v_sig := f_signWithEcdsaNistp256WithSha256(bit2oct(v_enc_msg), p_ca_sec_info.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("f_create_ca_certificate_nistP256_1: Signed template ", valueof(v_cert));
    
    // Final CA certificate
    return valueof(v_cert);
  } // End of function f_create_ca_certificate_nistP256_1
  
  /**
   * @desc Function to generate a CA certificate / BrainpoolP256
   * @see ETSI TS 103 097 V1.3.1 Clause 77.2.3 Root CA certificates
   */
  function f_create_ca_certificate_brainpoolP256_1(
                                                   out sec_info p_ca_sec_info
  ) runs on TCType return EtsiTs103097Certificate {
    var template (value) EtsiTs103097Certificate v_cert; // ETSI TS 103 097 V1.3.1 Clause 6 Bullet 1
    var charstring v_certId := "STF538 BrainpoolP256 Root Certificate";
    var HashAlgorithm v_self := sha256; // ETSI TS 103 097 V1.3.1 Clause 7.2.3 Root CA certificates Bullet 1
    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 })),
      valueof(m_appPermissions(38, { bitmapSsp := '830001'O }))
    };
    var SequenceOfPsidSspRange v_certIssuePermissions := { // ETSI TS 103 097 V1.3.1 Clause 7.2.3 Root CA certificates Bullet 3
      valueof(m_psidSspRange(1))
    };
    var HashedId8 v_sha256AndDigest;
    var Oct32 v_sig := int2oct(0, 32);
    var bitstring v_enc_msg := ''B;
      
    // Generate Private/Public keys
    f_generate_key_pair_brainpoolp256(p_ca_sec_info.private_key, p_ca_sec_info.public_key_x, p_ca_sec_info.public_key_y);
    // Store Private key in binary format
    // Fill Certificate template with the public key
  v_cert := m_etsiTs103097Certificate(
                                      m_issuerIdentifier_self(v_self),
                                      m_toBeSignedCertificate_ca(
                                                              { name := v_certId },
                                                              v_appPermissions,
                                                              {
                                                                m_psidGroupPermissions(
                                                                                       m_subjectPermissions_explicit(
                                                                                                                     v_certIssuePermissions
                                                                                                                    ))
                                                                },
                                                              m_verificationKeyIndicator_verificationKey(
                                                                                                         m_publicVerificationKey_ecdsaBrainpoolP256(
                                                                                                                                                    m_eccP256CurvePoint_uncompressed( // Signed by itself
                                                                                                                                                                                     p_ca_sec_info.public_key_x,
                                                                                                                                                                                     p_ca_sec_info.public_key_y
                                                                                                                                                                                    ))),
                                                              m_validityPeriod(
                                                                               17469212,
                                                                               m_duration_years(10)
                                                                              )
                                                             )
                                      );
    // Encode it ==> Get octetstring
  v_enc_msg := encvalue(v_cert.toBeSigned);
    // Sign the certificate using ECDSA/SHA-256 (BRAINPOOL P-256)
  v_sig := f_signWithEcdsaBrainpoolp256WithSha256(bit2oct(v_enc_msg), p_ca_sec_info.private_key);
  v_cert.signature_ := m_signature_ecdsaBrainpoolP256r1(
                                                        m_ecdsaP256Signature(
                                                                             m_eccP256CurvePoint_x_only(
                                                                                                        substr(v_sig, 0, 32)
                                                                                                        ),
                                                                             substr(v_sig, 32, 32)
                                                                            )
                                                      );
    log("f_create_ca_certificate_brainpoolP256_1: Signed template ", valueof(v_cert));
    
    // Final CA certificate
    return valueof(v_cert);
  } // End of function f_create_ca_certificate_brainpoolP256_1
  
  /**
   * @desc AA certificate / NistP256
   * @see ETSI TS 103 097 V1.3.1 Clause 7.2.1 Enrollment certificate
   */
  function f_create_aa_certificate_nistP256_1(
                                              in sec_info p_ca_sec_info,
                                              out sec_info p_aa_sec_info
  ) runs on TCType return EtsiTs103097Certificate {
    var template (value) EtsiTs103097Certificate v_cert; // ETSI TS 103 097 V1.3.1 Clause 6 Bullet 1
    var charstring v_certId := "STF538 NistP256 AA Certificate"; // ETSI TS 103 097 V1.3.1 Clause 7.2.2 Enrolment credential #5
    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 })),
      valueof(m_appPermissions(38, { bitmapSsp := '830001'O }))
    };
    var Oct32 v_sig := int2oct(0, 32);
    var bitstring v_enc_msg := ''B;
      
    // Generate Private/Public keys
    f_generate_key_pair_nistp256(p_aa_sec_info.private_key, p_aa_sec_info.public_key_x, p_aa_sec_info.public_key_y);
    // Store Private key in binary format
    // Fill Certificate template with the public key
  v_cert := m_etsiTs103097Certificate(
                                      m_issuerIdentifier_sha256AndDigest(p_ca_sec_info.hashid8),
                                      m_toBeSignedCertificate_aa(
                                                                 { name := v_certId },
                                                                 v_appPermissions,
                                                                 m_verificationKeyIndicator_verificationKey(
                                                                                                            m_publicVerificationKey_ecdsaNistP256(
                                                                                                                                                  m_eccP256CurvePoint_uncompressed(
                                                                                                                                                                                   p_aa_sec_info.public_key_x,
                                                                                                                                                                                   p_aa_sec_info.public_key_y
                                                                                                                                                                                   ))),
                                                                 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_enc_msg := encvalue(v_cert.toBeSigned);
    // Sign the certificate using ECDSA/SHA-256 (NIST P-256)
  v_sig := f_signWithEcdsaNistp256WithSha256(bit2oct(v_enc_msg), p_ca_sec_info.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("f_create_aa_certificate_nistP256_1: Signed template ", valueof(v_cert));
    
    // Final AA certificate
    return valueof(v_cert);
  } // End of function f_create_aa_certificate_nistP256_1

  /**
   * @desc AA certificate / BrainpoolP256
   * @see ETSI TS 103 097 V1.3.1 Clause 7.2.1 Enrollment certificate
   */
  function f_create_aa_certificate_brainpoolP256_1(
                                                   in sec_info p_ca_sec_info,
                                                   out sec_info p_aa_sec_info
  ) runs on TCType return EtsiTs103097Certificate {
    var template (value) EtsiTs103097Certificate v_cert; // ETSI TS 103 097 V1.3.1 Clause 6 Bullet 1
    var charstring v_certId := "STF538 BrainpoolP256 AA Certificate"; // ETSI TS 103 097 V1.3.1 Clause 7.2.2 Enrolment credential #5
    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 })),
      valueof(m_appPermissions(38, { bitmapSsp := '830001'O }))
    };
    var Oct32 v_sig := int2oct(0, 32);
    var bitstring v_enc_msg := ''B;
      
    // Generate Private/Public keys
    f_generate_key_pair_brainpoolp256(p_aa_sec_info.private_key, p_aa_sec_info.public_key_x, p_aa_sec_info.public_key_y);
    // Store Private key in binary format
    // Fill Certificate template with the public key
  v_cert := m_etsiTs103097Certificate(
                                      m_issuerIdentifier_sha256AndDigest(p_ca_sec_info.hashid8),
                                      m_toBeSignedCertificate_aa(
                                                                 { name := v_certId },
                                                                 v_appPermissions,
                                                                 m_verificationKeyIndicator_verificationKey(
                                                                                                            m_publicVerificationKey_ecdsaBrainpoolP256(
                                                                                                                                                       m_eccP256CurvePoint_uncompressed(
                                                                                                                                                                                        p_aa_sec_info.public_key_x,
                                                                                                                                                                                        p_aa_sec_info.public_key_y
                                                                                                                                                                                       ))),
                                                                 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_enc_msg := encvalue(v_cert.toBeSigned);
    // Sign the certificate using ECDSA/SHA-256 (BRAINPOOL P-256)
  v_sig := f_signWithEcdsaBrainpoolp256WithSha256(bit2oct(v_enc_msg), p_ca_sec_info.private_key);
  v_cert.signature_ := m_signature_ecdsaBrainpoolP256r1(
                                                        m_ecdsaP256Signature(
                                                                             m_eccP256CurvePoint_x_only(
                                                                                                        substr(v_sig, 0, 32)
                                                                                                        ),
                                                                             substr(v_sig, 32, 32)
                                                                            )
                                                );
    log("f_create_aa_certificate_brainpoolP256_1: Signed template ", valueof(v_cert));
    
    // Final AA certificate
    return valueof(v_cert);
  } // End of function f_create_aa_certificate_brainpoolP256_1

  /**
   * @desc AT certificate / NistP256
   * @see ETSI TS 103 097 V1.3.1 Clause 7.2.1 Authorization tickets
   */
  function f_create_at_certificate_nistP256_1(
                                              in sec_info p_aa_sec_info,
                                              out sec_info p_at_sec_info
  ) runs on TCType return EtsiTs103097Certificate {
    var template (value) EtsiTs103097Certificate v_cert; // ETSI TS 103 097 V1.3.1 Clause 6 Bullet 1
    var charstring v_certId := "STF538 NistP256 AT Certificate"; // ETSI TS 103 097 V1.3.1 Clause 7.2.1 Authorization tickets #2
    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 })),
      valueof(m_appPermissions(38, { bitmapSsp := '830001'O }))
    };
    var Oct32 v_sig := int2oct(0, 32);
    var bitstring v_enc_msg := ''B;
      
    // Generate Private/Public keys
    f_generate_key_pair_nistp256(p_at_sec_info.private_key, p_at_sec_info.public_key_x, p_at_sec_info.public_key_y);
    // Store Private key in binary format
    // Fill Certificate template with the public key
  v_cert := m_etsiTs103097Certificate(
                                      m_issuerIdentifier_sha256AndDigest(p_aa_sec_info.hashid8),
                                      m_toBeSignedCertificate_aa(
                                                                 { name := v_certId },
                                                                 v_appPermissions,
                                                                 m_verificationKeyIndicator_verificationKey(
                                                                                                            m_publicVerificationKey_ecdsaNistP256(
                                                                                                                                                  m_eccP256CurvePoint_uncompressed(
                                                                                                                                                                                   p_at_sec_info.public_key_x,
                                                                                                                                                                                   p_at_sec_info.public_key_y
                                                                                                                                                                                   ))),
                                                                 m_validityPeriod(
                                                                                  17469212,
                                                                                  m_duration_years(10)
                                                                                  ),
                                                                 m_geographicRegion_identifiedRegion(
                                                                                                     {
                                                                                                       m_identifiedRegion_country_only(12), 
                                                                                                       m_identifiedRegion_country_only(34)
                                                                                                       }
                                                                                                     )
                                                                 )
                                      );
    // Encode it ==> Get octetstring
    log("Encode template ", valueof(v_cert));
  v_enc_msg := encvalue(v_cert.toBeSigned);
    // Sign the certificate using ECDSA/SHA-256 (NIST P-256)
  v_sig := f_signWithEcdsaNistp256WithSha256(bit2oct(v_enc_msg), p_aa_sec_info.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("f_create_at_certificate_nistP256_1: Signed template ", valueof(v_cert));
    
    // Final AT certificate
    return valueof(v_cert);
  } // End of function f_create_at_certificate_nistP256_1

  /**
   * @desc AT certificate / BrainpoolP256
   * @see ETSI TS 103 097 V1.3.1 Clause 7.2.1 Authorization tickets
   */
  function f_create_at_certificate_brainpoolP256_1(
                                                   in sec_info p_aa_sec_info,
                                                   out sec_info p_at_sec_info
  ) runs on TCType return EtsiTs103097Certificate {
    var template (value) EtsiTs103097Certificate v_cert; // ETSI TS 103 097 V1.3.1 Clause 6 Bullet 1
    var charstring v_certId := "STF538 BrainpoolP256 AT Certificate"; // ETSI TS 103 097 V1.3.1 Clause 7.2.1 Authorization tickets #2
    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 })),
      valueof(m_appPermissions(38, { bitmapSsp := '830001'O }))
    };
    var Oct32 v_sig := int2oct(0, 32);
    var bitstring v_enc_msg := ''B;
      
    // Generate Private/Public keys
    f_generate_key_pair_brainpoolp256(p_at_sec_info.private_key, p_at_sec_info.public_key_x, p_at_sec_info.public_key_y);
    // Store Private key in binary format
    // Fill Certificate template with the public key
  v_cert := m_etsiTs103097Certificate(
                                      m_issuerIdentifier_sha256AndDigest(p_aa_sec_info.hashid8),
                                      m_toBeSignedCertificate_aa(
                                                                 { name := v_certId },
                                                                 v_appPermissions,
                                                                 m_verificationKeyIndicator_verificationKey(
                                                                                                            m_publicVerificationKey_ecdsaBrainpoolP256(
                                                                                                                                                       m_eccP256CurvePoint_uncompressed(
                                                                                                                                                                                        p_at_sec_info.public_key_x,
                                                                                                                                                                                        p_at_sec_info.public_key_y
                                                                                                                                                                                       ))),
                                                                 m_validityPeriod(
                                                                                  17469212,
                                                                                  m_duration_years(10)
                                                                                  ),
                                                                 m_geographicRegion_identifiedRegion(
                                                                                                     {
                                                                                                       m_identifiedRegion_country_only(12), 
                                                                                                       m_identifiedRegion_country_only(34)
                                                                                                       }
                                                                                                     )
                                                                 )
                                      );
    // Encode it ==> Get octetstring
    log("Encode template ", valueof(v_cert));
  v_enc_msg := encvalue(v_cert.toBeSigned);
    // Sign the certificate using ECDSA/SHA-256 (BRAINPOOL P-256)
  v_sig := f_signWithEcdsaBrainpoolp256WithSha256(bit2oct(v_enc_msg), p_aa_sec_info.private_key);
  v_cert.signature_ := m_signature_ecdsaBrainpoolP256r1(
                                                        m_ecdsaP256Signature(
                                                                             m_eccP256CurvePoint_x_only(
                                                                                                        substr(v_sig, 0, 32)
                                                                                                        ),
                                                                             substr(v_sig, 32, 32)
                                                                             )
                                                       );
    log("f_create_at_certificate_brainpoolP256_1: Signed template ", valueof(v_cert));
    
    // Final AT certificate
    return valueof(v_cert);
  } // End of function f_create_at_certificate_brainpoolP256_1

  function f_build_and_sign_secured_message_nistP256_1(
                                                       in template (value) GnNonSecuredPacket p_gnNonSecuredPacket,
                                                       in sec_info p_at_sec_info
  ) runs on TCType return EtsiTs103097Data {
    var octetstring v_raw_payload_to_be_signed;
    var template (value) ToBeSignedData v_toBeSignedData;
    var Oct32 v_sig := '0000000000000000000000000000000000000000000000000000000000000000'O;
    var EtsiTs103097Data v_secured_data;

    // Build the message to be signed
    v_raw_payload_to_be_signed := bit2oct(encvalue(p_gnNonSecuredPacket));
  v_toBeSignedData := m_toBeSignedData(
                                       m_signedDataPayload(
                                                           m_etsiTs103097Data_unsecured(v_raw_payload_to_be_signed)
                                                           ),
                                       m_headerInfo_gn(
                                                       -,
                                                       12345
                                                       )
                                       );
    // Signed it
  v_raw_payload_to_be_signed := bit2oct(encvalue(v_toBeSignedData));
  v_sig := f_signWithEcdsaNistp256WithSha256(v_raw_payload_to_be_signed, p_at_sec_info.private_key);
    // Finalize the secured message
  v_secured_data := valueof(
                            m_etsiTs103097Data_signed(
                                                      m_signedData(
                                                                   sha256,
                                                                   v_toBeSignedData,
                                                                   { digest := p_at_sec_info.hashid8 },
                                                                   m_signature_ecdsaNistP256(
                                                                                             m_ecdsaP256Signature(
                                                                                                                  m_eccP256CurvePoint_x_only(
                                                                                                                                             substr(v_sig, 0, 32)
                                                                                                                                             ),
                                                                                                                  substr(v_sig, 32, 32)
                                                                                                                  )
                                                                                             )
                                                                   )
                                                      )
                            );
    log("f_build_and_sign_secured_message_nistP256_1: v_secured_data = ", v_secured_data);
    
    return v_secured_data;
  } // End of function f_build_and_sign_secured_message_nistP256_1
  
  function f_build_and_sign_secured_message_brainpoolP256_1(
                                                            in template (value) GnNonSecuredPacket p_gnNonSecuredPacket,
                                                            in sec_info p_at_sec_info
  ) runs on TCType return EtsiTs103097Data {
    var octetstring v_raw_payload_to_be_signed;
    var template (value) ToBeSignedData v_toBeSignedData;
    var Oct32 v_sig := '0000000000000000000000000000000000000000000000000000000000000000'O;
    var template (value) EtsiTs103097Data v_secured_data;

    // Build the message to be signed
    v_raw_payload_to_be_signed := bit2oct(encvalue(p_gnNonSecuredPacket));
  v_toBeSignedData := m_toBeSignedData(
                                       m_signedDataPayload(
                                                           m_etsiTs103097Data_unsecured(v_raw_payload_to_be_signed)
                                                           ),
                                       m_headerInfo_gn(
                                                       -,
                                                       12345
                                                       )
                                       );
    // Signed it
  v_raw_payload_to_be_signed := bit2oct(encvalue(v_toBeSignedData));
  v_sig := f_signWithEcdsaBrainpoolp256WithSha256(v_raw_payload_to_be_signed, p_at_sec_info.private_key);
    // Finalize the secured message
  v_secured_data := m_etsiTs103097Data_signed(
                                              m_signedData(
                                                           sha256,
                                                           v_toBeSignedData,
                                                           { digest := p_at_sec_info.hashid8 },
                                                           m_signature_ecdsaBrainpoolP256r1(
                                                                                            m_ecdsaP256Signature(
                                                                                                                 m_eccP256CurvePoint_x_only(
                                                                                                                                            substr(v_sig, 0, 32)
                                                                                                                                            ),
                                                                                                                 substr(v_sig, 32, 32)
                                                                                                                 )
                                                                                            )
                                                           )
                                              );
    log("f_build_and_sign_secured_message_brainpoolP256_1: v_secured_data = ", v_secured_data);
    
    return valueof(v_secured_data);
  } // End of function f_build_and_sign_secured_message_brainpoolP256_1
  
} // End of module TestCodec_ChainOfCertificates
