LibItsSecurity_Functions.ttcn3 63.1 KB
Newer Older
garciay's avatar
garciay committed
/**
 *  @author   ETSI / STF481
 *  @version  $URL$
 *            $Id$
 *  @desc     Module containing functions for Security Protocol
 *
 */
module LibItsSecurity_Functions {
    import from LibCommon_BasicTypesAndValues all;
    // LibItsCommon
    import from LibItsCommon_Functions all;
    
    // LibItsSecurity
    import from LibItsSecurity_TypesAndValues all;
    import from LibItsSecurity_Templates all;
    import from LibItsSecurity_Pixits all;
    import from LibItsSecurity_TestSystem all;
garciay's avatar
garciay committed
    
    group helpersFunctions {
        * @desc    Produces a 256-bit (32-byte) hash value
        * @param   p_toBeHashedData Data to be used to calculate the hash value
        * @return  The hash value
        */
            in octetstring p_toBeHashedData
            return fx_hashWithSha256(p_toBeHashedData);
        } // End of function f_hashWithSha256
        * @desc    Produces a Elliptic Curve Digital Signature Algorithm (ECDSA) signaturee
        * @param   p_toBeSignedSecuredMessage    The data to be signed
        * @return  The signature value
        */
        function f_signWithEcdsaNistp256WithSha256(
            in Oct32 p_toBeSignedSecuredMessage
        ) runs on ItsSecurityBaseComponent return octetstring {
            return fx_signWithEcdsaNistp256WithSha256(
                p_toBeSignedSecuredMessage,
        } // End of function f_signWithEcdsaNistp256WithSha256
        * @desc Compute the HashedId8 value from the hash value
        * @param p_hash The hash value
        * @return The HashedId8 value
        * @verdict
        */
        function f_HashedId8FromSha256(
            in Oct32 p_hash
        ) return HashedId8 {
            return substr(p_hash, lengthof(p_hash) - 8, 8);
        } // End of function f_HashedId8FromSha256
        * @desc Compute the HashedId3 value from the HashedId8 value
        * @param p_hashp_hashedId8 The HashedId8 value
        * @return The HashedId3 value
        * @verdict Unchanged
        */
        function f_HashedId3FromHashedId8 (
            in HashedId8 p_hashedId8
        ) return HashedId3 {
            return substr(p_hashedId8, lengthof(p_hashedId8) - 3, 3);
        }  // End of function f_HashedId3FromHashedId8
        * @desc    Verify the signature of the specified data
        * @param   p_toBeVerifiedData          The data to be verified
        * @param   p_signature                 The signature
        * @param   p_ecdsaNistp256PublicKeyX   The public key (x coordinate)
        * @param   p_ecdsaNistp256PublicKeyY   The public key (y coordinate)
        * @return  true on success, false otherwise
        */
        function f_verifyWithEcdsaNistp256WithSha256(
            in octetstring p_toBeVerifiedData,
            in octetstring p_signature,
            in octetstring p_ecdsaNistp256PublicKeyX,
            in octetstring p_ecdsaNistp256PublicKeyY
        ) return boolean {
            return fx_verifyWithEcdsaNistp256WithSha256(
                p_toBeVerifiedData,
                p_signature,
                p_ecdsaNistp256PublicKeyX,
                p_ecdsaNistp256PublicKeyY);
        } // End of function f_verifyWithEcdsaNistp256WithSha256
        * @desc    Calculate digest over the certificate
        * @param   p_cert The certificate
        * @return  the digest
        * @see Draft ETSI TS 103 097 V1.1.6 Clause 4.2.13   HashedId8
        */
        function f_calculateDigestFromCertificate(
            in Certificate p_cert
            var octetstring v_toBeHashedData;
            var octetstring v_hash;
            var integer v_counter;
            
            // Search for digest in the signer_infos field first
            for (v_counter := 0; v_counter < lengthof(p_cert.signer_infos); v_counter := v_counter + 1) {
                if (p_cert.signer_infos[v_counter].type_ == e_certificate_digest_with_ecdsap256) {
                    return p_cert.signer_infos[v_counter].signerInfo.digest;
                }
            } // End of 'for' statement
            // Digest not found, compute it
            log ("f_calculateDigestFromCertificate: Not found in certificate, compute it");
            v_toBeHashedData := bit2oct(encvalue(p_cert));
            v_hash := f_hashWithSha256(v_toBeHashedData);
            return substr(v_hash, lengthof(v_hash) - 8, 8);
        group hostSignatureHelpers {
            * @desc Build a template of a secured beacon to be used for the Test Adapter secured beaconing processing
            */
            function f_buildSecuredMessagePayloadToBeSigned(
                in boolean p_includeCertificate := false
            ) runs on ItsSecurityBaseComponent return ToBeSignedSecuredMessage {
                // Local variables
                var template (value) ToBeSignedSecuredMessage v_toBeSignedSecuredMessage;
                
                // Build the beacon template
                if (p_includeCertificate == true) {
                    v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
                        c_security_profileOthers,
                        { // Field HeaderFields
                            m_header_field_signer_info(
                                m_signerInfo_certificate(
                                ) // End of template m_signerInfo_certificate
                            ), // End of template m_header_field_signer_info
                            m_header_field_generation_time(oct2int('BBBBBBBB'O)),   // To be replaced by TA with generation time
                            m_header_field_generation_location(
                            )
                        }, // End of field HeaderFields
                        {
                            m_payload_unsecured(
                                'AAAAAAAAAA'O                                       // To be replaced by TA with real payload
                            )
                        }, // End of field HeaderFields
                        e_signature
                    );
                } else {
                    v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
                        c_security_profileOthers,
                        { // Field HeaderFields
                            m_header_field_signer_info(
                                m_signerInfo_digest(
                                    vc_atCertificate.signer_infos[0].signerInfo.digest
                                ) // End of template m_signerInfo_certificate
                            ), // End of template m_header_field_signer_info
                            m_header_field_generation_time(oct2int('BBBBBBBB'O)),   // To be replaced by TA with generation time
                            m_header_field_generation_location(
                            )
                        }, // End of field HeaderFields
                        {
                            m_payload_unsecured(
                                'AAAAAAAAAA'O                                       // To be replaced by TA with real payload
                            )
                        }, // End of field HeaderFields
                        e_signature
                    );
                }
garciay's avatar
garciay committed
                return valueof(v_toBeSignedSecuredMessage);
            * @desc This function build and sign the SecureMessage part covered by the signature process
            * @param p_securedMessage      The signed  SecureMessage part
            * @param p_unsecuredPayload    The unsigned payload (e.g. a beacon)
            * @param p_signerInfoType      Add digest or AT certificate or certificate chain
            * @param p_headerFields        HeaderFields to be inserted in the message
            * @param p_configId            The configuration identifier to be used
            * @param p_addMissingHeaders   Whether to add mandatory headers not present in p_headerFields
            * @param p_certificateName     The certificate identifier to be used. Default: TA_CONFIG_A
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
            function f_buildGnSecuredCam(
                out template (value) SecuredMessage p_securedMessage,
                in octetstring p_unsecuredPayload,
                in template (omit) SignerInfoType p_signerInfoType := e_certificate_digest_with_ecdsap256,
                in template (omit) HeaderFields p_headerFields := omit,
                in template (omit) charstring p_certificateName := omit,
                in boolean p_addMissingHeaders := true
            ) runs on ItsSecurityBaseComponent return boolean {
                
                // Local variables
                var Certificate v_aaCertificate, v_atCertificate;
                var octetstring v_secPayload, v_signature;
                var Oct32 v_hash;
                var template (value) ToBeSignedSecuredMessage v_toBeSignedSecuredMessage;
                var integer i, j, k, n;
                var HeaderFields v_mandatoryHeaders := {};
                var template (value) HeaderFields v_headerFields := {};
                var template (value) HeaderField v_signerInfo;
                // Sanity check
                if (ispresent(p_certificateName) and (p_certificateName != "TA_CONFIG_A")) {
                    if (f_readCertificate(p_certificateName & ".AA_CERT", v_aaCertificate) == false) {
                    if (f_readCertificate(p_certificateName & ".AT_CERT", v_atCertificate) == false) {
                } else {
                    v_aaCertificate := vc_aaCertificate;
                    v_atCertificate := vc_atCertificate;
                }
                
                if(p_addMissingHeaders == false) {
                    v_toBeSignedSecuredMessage.header_fields := p_headerFields;
                }
                else {
                    // Prepare mandatory headers
                    if (p_signerInfoType == e_certificate) { // Add the AT certificate
                        v_signerInfo := m_header_field_signer_info(m_signerInfo_certificate(v_atCertificate));
                    }
                    if (p_signerInfoType == e_certificate_chain) { // Add the AT certificate + AA Certificate
                        v_signerInfo := m_header_field_signer_info(
                            m_signerInfo_certificates(
                                {
                                    v_aaCertificate,
                        );
                    }
                    if (p_signerInfoType == e_certificate_digest_with_ecdsap256) { // Add the AT certificate digest
                        v_signerInfo := m_header_field_signer_info(m_signerInfo_digest(v_atCertificate.signer_infos[0].signerInfo.digest));
                    }
                    v_mandatoryHeaders := {
                        v_signerInfo,
                        m_header_field_generation_time(f_getCurrentTime()),
                        m_header_field_message_type(c_messageType_CAM)
                    }
                                                                                
                    if(not(ispresent(p_headerFields))) {
                        v_toBeSignedSecuredMessage.header_fields := v_mandatoryHeaders;
                    }
                    else {
                        // Merge p_headerFields and v_mandatoryHeaders into v_headerFields
                        
                        i := 0; // index for p_headerFields
                        j := 0; // index for v_mandatoryHeaders
                        k := 0; // index for v_headerFields
                        
                        // Special processing for signer_info
                        if(lengthof(p_headerFields) > 0 and p_headerFields[i].type_ == e_signer_info) {
                            v_headerFields[k] := p_headerFields[i];
                            k := k + 1;
                            i := i + 1;
                        }
                        
                        for(j:=j; j < lengthof(v_mandatoryHeaders); j:=j+1) {
                            // Search for mandatory header in p_HeaderFields
                            for(n:=0; n < lengthof(p_headerFields); n:=n+1) {
                                if(p_headerFields[n].type_ == v_mandatoryHeaders[j].type_) {
                                    // mandatory header already in p_HeaderFields
                                    break;
                                }
                            }
                            if(n >= lengthof(p_headerFields)) {
                                if(v_mandatoryHeaders[j].type_ != e_signer_info) {
                                    // Add headers from p_headerFields having lower number than mandatory header
                                    for(n:=i ; n < lengthof(p_headerFields) and p_headerFields[n].type_ < v_mandatoryHeaders[j].type_; n:=n+1) {
                                        v_headerFields[k] := p_headerFields[n];
                                        k := k + 1;
                                        i := i + 1;
                                }
                                // Add mandatory header
                                v_headerFields[k] := v_mandatoryHeaders[j];
                                k := k + 1;
                                j := j + 1;
                            }
                        }
                        
                        // Add remaining headers from p_HeaderFields
                        for(i:=i; i < lengthof(p_headerFields); i:=i+1) {
                            // Add headers from p_headerFields having lower number than mandatory header
                            v_headerFields[k] := p_headerFields[i];
                            k := k + 1;
                        }
                    }
                v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
                    c_security_profileCAMs,
                    v_headerFields,
                    {
                        m_payload_unsecured(
                            p_unsecuredPayload
                        )
                    }, // End of field HeaderFields
                    e_signature
                );
                
                v_secPayload := bit2oct(encvalue(v_toBeSignedSecuredMessage));
                
                // Calculate the hash of the SecuredMessage payload to be signed
                v_hash := f_hashWithSha256(v_secPayload);
                
                // Signed payload
                v_signature := f_signWithEcdsaNistp256WithSha256(
                    v_hash
                );
                
                p_securedMessage := md_secureMessage_profileCam( // See Clause 7.1   Security profile for CAMs
                    v_toBeSignedSecuredMessage.header_fields,
                    v_toBeSignedSecuredMessage.payload_fields,
                    {
                        m_trailer_field_signature(
                            m_signature(
                                m_ecdsaSignature(
                                    m_eccPointecdsa_nistp256_with_sha256_y_coordinate_only(
                                        substr(v_signature, 2, 32)
                                    ),
                                    substr(v_signature, 34, 32)
                                )
                ); // End of template m_securedMessage_profileCam
            * @desc This function build and sign the SecureMessage part covered by the signature process
            * @param p_securedMessage      The signed  SecureMessage part
            * @param p_unsecuredPayload    The unsigned payload (e.g. a beacon)
            * @param p_threeDLocation      The ThreeDLocation value
            * @param p_addCertificate      Set to true to add the AT certificate in header fields. Otherwise, only the AA certificate digest will be added
            * @param p_headerFields        Additional HeaderFields
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
            function f_buildGnSecuredDenm(
                out template (value) SecuredMessage p_securedMessage,
                in octetstring p_unsecuredPayload,
                in ThreeDLocation p_threeDLocation,
                in template (omit) boolean p_addCertificate := false,
                in template (omit) HeaderFields p_headerFields := omit
            ) runs on ItsSecurityBaseComponent return boolean {
                
                // Local variables
                var octetstring v_secPayload, v_signature;
                var Oct32 v_hash;
                var template (value) ToBeSignedSecuredMessage v_toBeSignedSecuredMessage;
                 
                // Create SecuredMessage payload to be signed
garciay's avatar
garciay committed
                if (valueof(p_addCertificate) == true) { // Add the AA certificate
                    v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
                        c_security_profileDENMs,
                        { // Field HeaderFields
                            m_header_field_signer_info(
                                m_signerInfo_certificate(
                                ) // End of template m_signerInfo_certificate
                            ), // End of template m_header_field_signer_info
                            m_header_field_generation_time(f_getCurrentTime()),
                            m_header_field_generation_location(
                                p_threeDLocation
                            ),
                            m_header_field_message_type(c_messageType_DENM)
                        }, // End of field HeaderFields
                        {
                            m_payload_unsecured(
                                p_unsecuredPayload
                            )
                        }, // End of field HeaderFields
                        e_signature
                    );
                } else { // Add the AA certificate digest
                    v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
                        c_security_profileDENMs,
                        { // Field HeaderFields
                            m_header_field_signer_info(
                                m_signerInfo_digest(
                                    vc_atCertificate.signer_infos[0].signerInfo.digest
                                ) // End of template m_signerInfo_digest
                            ), // End of template m_header_field_digest
                            m_header_field_generation_time(f_getCurrentTime()),
                            m_header_field_generation_location(
                                p_threeDLocation
                            ),
                            m_header_field_message_type(c_messageType_DENM)
                        }, // End of field HeaderFields
                        {
                            m_payload_unsecured(
                                p_unsecuredPayload
                            )
                        }, // End of field HeaderFields
                        e_signature
                    );
                }
                // Add additional header fields if any
                if (ispresent(p_headerFields) == true) {
                    var integer v_addItemIndex := lengthof(v_toBeSignedSecuredMessage.header_fields);
                    var integer v_counter;
                    
                    for (v_counter := 0; v_counter < lengthof(p_headerFields); v_counter := v_counter + 1) {
                        v_toBeSignedSecuredMessage.header_fields[v_addItemIndex] := p_headerFields[v_counter];
                        v_addItemIndex := v_addItemIndex + 1;
                    } // End of 'for' statement
                }
                log("v_toBeSignedSecuredMessage= ", v_toBeSignedSecuredMessage);
                
                v_secPayload := bit2oct(encvalue(v_toBeSignedSecuredMessage));
                
                // Calculate the hash of the SecuredMessage payload to be signed
                v_hash := f_hashWithSha256(v_secPayload);
                
                // Signed payload
                v_signature := f_signWithEcdsaNistp256WithSha256(
                    v_hash
                );
                
                p_securedMessage := md_secureMessage_profileDenm( // See Clause 7.2   Security profile for DENMs
                    v_toBeSignedSecuredMessage.header_fields,
                    v_toBeSignedSecuredMessage.payload_fields,
                    {
                        m_trailer_field_signature(
                            m_signature(
                                m_ecdsaSignature(
                                    m_eccPointecdsa_nistp256_with_sha256_y_coordinate_only(
                                        substr(v_signature, 2, 32)
                                    ),
                                    substr(v_signature, 34, 32)
                                )
                ); // End of template m_securedMessage_profileDenm
                
                return true;
            } // End of function f_buildGnSecuredDenm
            * @desc This function build and sign the SecureMessage part covered by the signature process
            * @param p_securedMessage      The signed  SecureMessage part
            * @param p_unsecuredPayload    The unsigned payload (e.g. a beacon)
            * @param p_threeDLocation      The ThreeDLocation value
            * @param p_addCertificate      Set to true to add the AT certificate in header fields. Otherwise, only the AA certificate digest will be added
            * @param p_headerFields        Additional HeaderFields
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
            function f_buildGnSecuredOtherMessage(
                out template (value) SecuredMessage p_securedMessage,
                in octetstring p_unsecuredPayload,
                in ThreeDLocation p_threeDLocation,
                in template (omit) boolean p_addCertificate := false,
                in template (omit) HeaderFields p_headerFields := omit
            ) runs on ItsSecurityBaseComponent return boolean {
                
                // Local variables
                var octetstring v_secPayload, v_signature;
                var Oct32 v_hash;
                var template (value) ToBeSignedSecuredMessage v_toBeSignedSecuredMessage;
                 
                // Create SecuredMessage payload to be signed
garciay's avatar
garciay committed
                if (valueof(p_addCertificate) == true) { // Add the AA certificate
                    v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
                        c_security_profileOthers,
                        { // Field HeaderFields
                            m_header_field_signer_info(
                                m_signerInfo_certificate(
                                ) // End of template m_signerInfo_certificate
                            ), // End of template m_header_field_signer_info
                            m_header_field_generation_time(f_getCurrentTime()),
                            m_header_field_generation_location(
                                p_threeDLocation
                            )
                        }, // End of field HeaderFields
                        {
                            m_payload_unsecured(
                                p_unsecuredPayload
                            )
                        }, // End of field HeaderFields
                        e_signature
                    );
                } else { // Add the AA certificate digest
                    v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
                        c_security_profileOthers,
                        { // Field HeaderFields
                            m_header_field_signer_info(
                                m_signerInfo_digest(
                                    vc_atCertificate.signer_infos[0].signerInfo.digest
                                ) // End of template m_signerInfo_digest
                            ), // End of template m_header_field_digest
                            m_header_field_generation_time(f_getCurrentTime()),
                            m_header_field_generation_location(
                                p_threeDLocation
                            )
                        }, // End of field HeaderFields
                        {
                            m_payload_unsecured(
                                p_unsecuredPayload
                            )
                        }, // End of field HeaderFields
                        e_signature
                    );
                }
                // Add additional header fields if any
                if (ispresent(p_headerFields) == true) {
                    var integer v_addItemIndex := lengthof(v_toBeSignedSecuredMessage.header_fields);
                    var integer v_counter;
                    
                    for (v_counter := 0; v_counter < lengthof(p_headerFields); v_counter := v_counter + 1) {
                        v_toBeSignedSecuredMessage.header_fields[v_addItemIndex] := p_headerFields[v_counter];
                        v_addItemIndex := v_addItemIndex + 1;
                    } // End of 'for' statement
                }
                log("v_toBeSignedSecuredMessage= ", v_toBeSignedSecuredMessage);
                
                v_secPayload := bit2oct(encvalue(v_toBeSignedSecuredMessage));
                
                // Calculate the hash of the SecuredMessage payload to be signed
                v_hash := f_hashWithSha256(v_secPayload);
                
                // Signed payload
                v_signature := f_signWithEcdsaNistp256WithSha256(
                    v_hash
                );
                
                p_securedMessage := md_securedMessage_profileOther( // See Clause 7.3   Generic security profile for other signed messages
                    v_toBeSignedSecuredMessage.header_fields,
                    v_toBeSignedSecuredMessage.payload_fields,
                    {
                        m_trailer_field_signature(
                            m_signature(
                                m_ecdsaSignature(
                                    m_eccPointecdsa_nistp256_with_sha256_y_coordinate_only(
                                        substr(v_signature, 2, 32)
                                    ),
                                    substr(v_signature, 34, 32)
                                )
                ); // End of template md_securedMessage_profileOther
                
                return true;
            } // End of function f_buildGnSecuredOtherMessage
        } // End of group hostSignatureHelpers
        
        group deviceSignatureHelpers {
             
garciay's avatar
garciay committed
            /**
            * @desc Verify the signature of the provided certificate
            * @param p_certificateToBeVerified Certificate to be verified
            * @param p_publicKey               Public key to verify the certificate signature
            * @return true on success, false otherwise
            * @verdict
            */
garciay's avatar
garciay committed
            function f_verifyCertificateSignatureWithPublicKey(
                in template (value) Certificate p_certificateToBeVerified,
                in template (value) PublicKey   p_publicKey
            ) return boolean {
                // Local variables
                var octetstring toBeVerifiedData;
                var octetstring v_signature;
                var boolean v_result := false;
                var template (value) ToBeSignedCertificate v_toBeSignedCertificate;
                
                // Create Certificate payload to be verified
                v_toBeSignedCertificate := m_toBeSignedCertificate(p_certificateToBeVerified);
                toBeVerifiedData := bit2oct(encvalue(v_toBeSignedCertificate));
                
                // Build the signature
                v_signature :=
                '0000'O &
                valueof(p_certificateToBeVerified.signature_.signature_.ecdsa_signature.r.x) &
                valueof(p_certificateToBeVerified.signature_.signature_.ecdsa_signature.s);
                
                // Verify the certificate
                v_result := f_verifyWithEcdsaNistp256WithSha256(
                    toBeVerifiedData,
                    v_signature,
garciay's avatar
garciay committed
                    valueof(p_publicKey.public_key.eccPoint.x),
                    valueof(p_publicKey.public_key.eccPoint.y.y)
                return v_result;
            } // End of finction f_verifyCertificateSignatureWithPublicKey
            * @desc Verify the signature of the provided secured message
            * @param p_certificateToBeVerified Certificate to be verified
            * @param p_issuingCertificate      Issuing certificate
            * @return true on success, false otherwise
            * @verdict
            */
            function f_verifyCertificateSignatureWithIssuingCertificate(
                in template (value) Certificate p_certificateToBeVerified,
                in template (value) Certificate p_issuingCertificate
                var integer v_counter;
                
                for (v_counter := 0; v_counter < lengthof(p_issuingCertificate.subject_attributes); v_counter := v_counter + 1) {
garciay's avatar
garciay committed
                    if (valueof(p_issuingCertificate.subject_attributes[v_counter].type_) == e_verification_key) {
                        return f_verifyCertificateSignatureWithPublicKey(
                            p_certificateToBeVerified,
                            p_issuingCertificate.subject_attributes[v_counter].attribute.key);
                    }
                } // End of 'for' statement
                
                return false;
            } // End of function f_verifyCertificateSignatureWithIssuingCertificate
            
            * @desc Verify the signature of the provided secured message
            * @param p_securedMessage  The message to be verified
            * @param p_publicKey       The ECDSA public key to verify a signature
            * @param p_certificate     Certificate to be used to verify the message
            * @return true on success, false otherwise
            * @verdict
            */
            function f_verifyGnSecuredMessageSignatureWithPublicKey(
                in template (value) SecuredMessage p_securedMessage,
                in template (value) PublicKey p_publicKey
            ) return boolean {
                
                // Local variables
                var octetstring v_secPayload;
                var octetstring v_signedData;
                var Oct32 v_hash;
                var integer v_counter;
                var boolean v_result := false;
                var template (value) ToBeSignedSecuredMessage v_toBeSignedSecuredMessage;
garciay's avatar
garciay committed
//                log(">>> f_verifyGnSecuredMessageSignatureWithPublicKey: ", p_securedMessage);
                // Create SecuredMessage payload to be signed
                v_toBeSignedSecuredMessage := m_toBeSignedSecuredMessage(
garciay's avatar
garciay committed
                    valueof(p_securedMessage.security_profile),
                    p_securedMessage.header_fields,
                    p_securedMessage.payload_fields,
                v_secPayload := bit2oct(encvalue(v_toBeSignedSecuredMessage));
garciay's avatar
garciay committed
//                log("f_verifyGnSecuredMessageSignatureWithPublicKey: v_secPayload=", v_secPayload);
                
                // Calculate the hash of the SecuredMessage payload to be signed
                v_hash := fx_hashWithSha256(v_secPayload);
garciay's avatar
garciay committed
//                log("f_verifyGnSecuredMessageSignatureWithPublicKey: v_hash=", v_hash);
                
                // Verify payload
                for (v_counter := 0; v_counter < lengthof(p_securedMessage.trailer_fields); v_counter := v_counter + 1) {
garciay's avatar
garciay committed
                    var SecuredMessage v_securedMessage := valueof(p_securedMessage);
                        (v_securedMessage.trailer_fields[v_counter].type_ == e_signature) and
garciay's avatar
garciay committed
                        (v_securedMessage.trailer_fields[v_counter].trailerField.signature_.algorithm == e_ecdsa_nistp256_with_sha256)
                        v_signedData :=
                        '0000'O &
                        v_securedMessage.trailer_fields[v_counter].trailerField.signature_.signature_.ecdsa_signature.r.x &
                        v_securedMessage.trailer_fields[v_counter].trailerField.signature_.signature_.ecdsa_signature.s;
garciay's avatar
garciay committed
//                        log("f_verifyGnSecuredMessageSignatureWithPublicKey: v_signedData=", v_signedData);
                        v_result := f_verifyWithEcdsaNistp256WithSha256(
                            v_hash,
                            v_signedData,
garciay's avatar
garciay committed
                            valueof(p_publicKey.public_key.eccPoint.x),
                            valueof(p_publicKey.public_key.eccPoint.y.y)
garciay's avatar
garciay committed
                        break;
                    }
                } // End of 'for' statement
                
garciay's avatar
garciay committed
//                log("f_verifyGnSecuredMessageSignatureWithPublicKey: v_result=", v_result);
                return v_result;
            } // End of function f_verifyCertificateSignatureWithPublicKey
            
            /**
            * @desc Verify the signature of the provided secured message
            * @param p_securedMessage
            * @param p_certificate     Certificate to be used to verify the message
            * @return true on success, false otherwise
            * @verdict
            */
            function f_verifyGnSecuredMessageSignatureWithCertificate(
                in template (value) SecuredMessage p_securedMessage,
                in template (value) Certificate p_certificate
                var integer v_counter;
                
                for (v_counter := 0; v_counter < lengthof(p_certificate.subject_attributes); v_counter := v_counter + 1) {
garciay's avatar
garciay committed
                    var SubjectAttribute v_subjectAttribute := valueof(p_certificate.subject_attributes[v_counter]);
                    
//                    log("f_verifyGnSecuredMessageSignatureWithCertificate: processing ", v_subjectAttribute);
                    if (v_subjectAttribute.type_ == e_verification_key) {
//                    if (valueof(p_certificate.subject_attributes[v_counter].type_) == e_verification_key) {
                        return f_verifyGnSecuredMessageSignatureWithPublicKey(
                            p_securedMessage,
                            p_certificate.subject_attributes[v_counter].attribute.key);
                    }
                } // End of 'for' statement
                
                return false;
            } // End of function f_verifyGnSecuredOtherMessageWithDeviceCertificate
        } // End of group deviceSignatureHelpers
filatov's avatar
filatov committed
        group messageGetters {
            * @desc    return SecuredMessage header field of given type or null if none
            * @param   p_msg the SecuredMessage
            * @param   p_type header field type
            * @return  HeaderField of given type if any or null
            */
            function f_getMsgHeaderField(
                in  SecuredMessage p_securedMessage,
                in  HeaderFieldType p_headerFieldType,
                out HeaderField p_return
                var integer v_length := lengthof(p_securedMessage.header_fields);
                
                for (var integer i := 0; i < v_length; i := i + 1) {
                    if (p_securedMessage.header_fields[i].type_ == p_headerFieldType) {
                        p_return := p_securedMessage.header_fields[i];
                        return true;
                
                log("f_getMsgHeaderField: return false");
            * @desc    return SignerInfo SecuredMessage field
            */
            function f_getMsgSignerInfo (
                in SecuredMessage p_securedMessage,
                out SignerInfo p_signerInfo
            ) return boolean {
                var HeaderField v_hf;
                
                if (f_getMsgHeaderField(p_securedMessage, e_signer_info, v_hf) == true) {
                    if (isbound(v_hf.headerField.signer)) {
                        p_signerInfo := v_hf.headerField.signer;
                        return true;
                    }
                
                log("f_getMsgSignerInfo: return false");
garciay's avatar
garciay committed
            
filatov's avatar
filatov committed
        }// End of group messageGetters
        
        group certificateGetters {
            * @desc Set the gneration location ase defined in Draft ETSI TS 103 097 V1.1.6
            * @param p_latitude    The latitude value
            * @param p_longitude   The longitude value
            * @param p_elevation   The elevation value
            * @verdict Unchanged
            */
            function f_setGenerationLocation(
                in WGSLatitude p_latitude,
                in WGSLongitude p_longitude,
                in Oct2 p_elevation := '0000'O
            ) runs on ItsSecurityBaseComponent {
                vc_location := {
                    p_latitude,
                    p_longitude,
                    p_elevation
                }
            } // End of function f_setGenerationLocation
            
            * @desc    Load in memory cache the certificates available
            * @param   p_configId      A configuration identifier
            * @remark  This method SHALL be call before any usage of certificates
            * @return  true on success, false otherwise
            */
            function f_loadCertificates(
                in charstring p_configId
            ) runs on ItsSecurityBaseComponent return boolean {
                var boolean v_result;
                
                // Setup certificates memory cache
                if (fx_loadCertificates(PX_ROOT_PATH_FOR_SECURITY, p_configId) == true) {
                    // Setup security component variables
                    f_readCertificate("TA_CONFIG_A.AA_CERT", vc_aaCertificate);
                    f_readCertificate("TA_CONFIG_A.AT_CERT", vc_atCertificate);
                    f_readPrivateKeys("TA_CONFIG_A.PRIVATE_KEYS", vc_signingPrivateKey, vc_encryptPrivateKey);
                    
                    return true;
                }
                return false;
            } // End of function f_loadCertificates
            
            /**
            * @desc    Unload from memory cache the certificates available
            * @return  true on success, false otherwise
            */
            function f_unloadCertificates() runs on ItsSecurityBaseComponent return boolean {
                // Reset security component variables
                vc_signingPrivateKey := '0000000000000000000000000000000000000000000000000000000000000000'O;
                vc_encryptPrivateKey := '0000000000000000000000000000000000000000000000000000000000000000'O;
                // Clear certificates memory cache
                return fx_unloadCertificates();
            } // End of function f_unloadCertificates
            * @desc    Read the specified certificate
            * @param   p_certificateId the certificate identifier
            * @param   p_certificate   the expected certificate
            * @return  true on success, false otherwise
            */
            function f_readCertificate(
                in charstring p_certificateId,
                out Certificate p_certificate
            ) runs on ItsSecurityBaseComponent return boolean {
                var octetstring v_certificate;
                
                if (fx_readCertificate(p_certificateId, v_certificate) == true) {
                    var integer v_result := decvalue(oct2bit(v_certificate), p_certificate);
                    if (v_result == 0) {
                        return true;
                    }
                }
                
                return false;
            } // End of function f_readCertificate
            
            /**
            * @desc    Read the private keys for the specified certificate
            * @param   p_keysId            the keys identifier
            * @param   p_signingPrivateKey the signing private key
            * @param   p_encryptPrivateKey the encrypt private key
            * @return  true on success, false otherwise
            */
            function f_readPrivateKeys(
                in charstring p_keysId,
                out Oct32 p_signingPrivateKey,
                out Oct32 p_encryptPrivateKey
            ) runs on ItsSecurityBaseComponent return boolean {
                return fx_readPrivateKeys(p_keysId, p_signingPrivateKey, p_encryptPrivateKey);
            } // End of function f_readPrivateKeys
            function f_getCertificateValidityRestriction(
                in template (value) Certificate p_cert,
                in ValidityRestrictionType p_type,
                out ValidityRestriction p_return
            ) return boolean {
                for (var integer i := 0; i < lengthof(p_cert.validity_restrictions); i := i + 1) {
                    if (valueof(p_cert).validity_restrictions[i].type_ == p_type ) {
                        p_return := valueof(p_cert).validity_restrictions[i];
                        return true;
filatov's avatar
filatov committed
                    }
                }
            } // End of function f_getCertificateValidityRestriction
filatov's avatar
filatov committed
            
            function f_getCertificateSignerInfo (
                in template (value) Certificate p_cert,
                out SignerInfo p_si
                if (isbound(valueof(p_cert).signer_infos)
                    and lengthof(p_cert.signer_infos) > 0) {
                    p_si := valueof(p_cert).signer_infos[0];
                    return true;
filatov's avatar
filatov committed
                }
filatov's avatar
filatov committed
            }
            
            function f_getCertificateSubjectAttribute(
                in template (value) Certificate p_cert,
                in SubjectAttributeType p_type,
                out SubjectAttribute p_return
            ) return boolean {
                for (var integer i := 0; i < lengthof(p_cert.subject_attributes); i := i + 1) {
                    if (valueof(p_cert).subject_attributes[i].type_ == p_type ) {
                        p_return := valueof(p_cert).subject_attributes[i];
                        return true;
                    }
                }
                return false;
            }
            
filatov's avatar
filatov committed
        }// End of group certificateGetters
    } // End of group helpersFunctions

    group externalFunctions {
        
        group signing {
            
            /**
            * @desc    Produces a 256-bit (32-byte) hash value
            * @param   p_toBeHashedData Data to be used to calculate the hash value
            * @return  The hash value
            */
            external function fx_hashWithSha256(in octetstring p_toBeHashedData) return Oct32;
            
            /**
            * @desc    Produces a Elliptic Curve Digital Signature Algorithm (ECDSA) signaturee
            * @param   p_toBeSignedSecuredMessage    The data to be signed
            * @param   p_privateKey        The private key
            * @return  The signature value
            */
            external function fx_signWithEcdsaNistp256WithSha256(in octetstring p_toBeSignedSecuredMessage, in octetstring/*UInt64*/ p_privateKey) return octetstring;
            
            /**
            * @desc    Verify the signature of the specified data
            * @param   p_toBeVerifiedData          The data to be verified
            * @param   p_signature                 The signature
            * @param   p_ecdsaNistp256PublicKeyX   The public key (x coordinate)
            * @param   p_ecdsaNistp256PublicKeyY   The public key (y coordinate)
            * @return  true on success, false otherwise
            */
            external function fx_verifyWithEcdsaNistp256WithSha256(in octetstring p_toBeVerifiedData, in octetstring p_signature, in octetstring p_ecdsaNistp256PublicKeyX, in octetstring p_ecdsaNistp256PublicKeyY) return boolean;
            
            /**
            * @desc    Produce a new public/private key pair based on Elliptic Curve Digital Signature Algorithm (ECDSA) algorithm.
            *          This function should not be used by the ATS
            * @param   p_privateKey    The new private key value
            * @param   p_publicKeyX    The new public key value (x coordinate)
            * @param   p_publicKeyX    The new public key value (y coordinate)
            * @return  true on success, false otherwise
            */
            external function fx_generateKeyPair(out octetstring/*UInt64*/ p_privateKey, out octetstring p_publicKeyX, out octetstring p_publicKeyY) return boolean;
            
        } // End of group signing
        group encryption {
            
        } // End of group encryption
        group certificatesLoader {
            
            /**
            * @desc    Load in memory cache the certificates available in the specified directory
            * @param   p_rootDirectory Root directory to access to the certificates identified by the certificate ID
            * @param   p_configId      A configuration identifier
            * @remark  This method SHALL be call before any usage of certificates
            * @return  true on success, false otherwise
            */
            external function fx_loadCertificates(in charstring p_rootDirectory, in charstring p_configId) return boolean;
            
            /**
            * @desc    Unload from memory cache the certificates
            * @return  true on success, false otherwise
            */
            external function fx_unloadCertificates() return boolean;
            * @desc    Read the specified certificate
            * @param   p_certificateId the certificate identifier
            * @param   p_certificate   the expected certificate
            * @return  true on success, false otherwise
            */
            external function fx_readCertificate(in charstring p_certificateId, out octetstring p_certificate) return boolean;
            
            /**
            * @desc    Read the private keys for the specified certificate
            * @param   p_keysId            the keys identifier
            * @param   p_signingPrivateKey the signing private key
            * @param   p_encryptPrivateKey the encrypt private key
            * @return  true on success, false otherwise
            */
            external function fx_readPrivateKeys(in charstring p_keysId, out Oct32 p_signingPrivateKey, out Oct32 p_encryptPrivateKey) return boolean;
            
        } // End of group certificatesLoader
        
        group geodesic {
            
            /**
            * @desc    Check that given polygon doesn't have neither self-intersections nor holes.
            * @param   p_region   Polygonal Region
            * @return  true on success, false otherwise
            * @verdict Unchanged
            */
garciay's avatar
garciay committed
            external function fx_isValidPolygonalRegion(in PolygonalRegion p_region) return boolean;
            * @desc Check if a polygonal regin is inside another one
            * @param p_parent  The main polygonal region
            * @param p_region  The polygonal region to be included
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
garciay's avatar
garciay committed
            external function fx_isPolygonalRegionInside(in PolygonalRegion p_parent, in PolygonalRegion p_region) return boolean;
            * @desc Check that the location is inside a circular region
            * @param p_region      The circular region to consider
            * @param p_location    The device location
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
garciay's avatar
garciay committed
            external function fx_isLocationInsideCircularRegion(in CircularRegion p_region, in ThreeDLocation p_location) return boolean;
            * @desc Check that the location is inside a rectangular region
            * @param p_region      The rectangular region to consider
            * @param p_location    The device location
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
garciay's avatar
garciay committed
            external function fx_isLocationInsideRectangularRegion(in RectangularRegions p_region, in ThreeDLocation p_location) return boolean;
            * @desc Check that the location is inside a polygonal region
            * @param p_region      The polygonal region to consider
            * @param p_location    The device location
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
            external function fx_isLocationInsidePolygonalRegion(in PolygonalRegion p_region, in ThreeDLocation p_location) return boolean;
            * @desc Check if the location is inside an identified region
            * @param p_region      The identified region to consider
            * @param p_location    The device location
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
garciay's avatar
garciay committed
            external function fx_isLocationInsideIdentifiedRegion(in IdentifiedRegion p_region, in ThreeDLocation p_location) return boolean;
            * @desc Convert a spacial coordinate from DMS to Dms
            * @param p_degrees The degrees (D)
            * @param p_minutes The minutes (M)
            * @param p_seconds The seconds (S)
            * @param p_latlon  The latitude/longitude: (N|S|E|W)
            * @return The decimal coordinate on success, 0.0, otherwise
            * @verdict Unchanged
            */
            external function fx_dms2dd(in Int p_degrees, in Int p_minutes, in float p_seconds, in Oct1 p_latlon) return float;
        } // End of group geodesic
        
    } // End of group externalFunctions
    
filatov's avatar
filatov committed
    group geometryFunctions {
        
        /**
        * @desc    Check that given location is valid
        * @param   p_location    location to be checked
        * @return  true on success, false otherwise
        */
        function f_isValidTwoDLocation(
            in template (value) TwoDLocation p_location
filatov's avatar
filatov committed
        ) return boolean {
            (valueof(p_location).longitude != c_maxLongitude + 1) and
            (valueof(p_location).latitude != c_maxLatitude + 1);
        } // End of function f_isValidTwoDLocation
filatov's avatar
filatov committed
        /**
        * @desc    Check that two given rectanlular regions are intersected
        *          Note: Regions must be normalized(northwest.latitude >= southeast.latitude)
        *          TODO: Add case when
        * @param   p_r1    Region 1
        * @param   p_r2    Region 2
        *
        * @return  true on success, false otherwise
        */
        function f_isRectangularRegionsIntersected(
            in template (value) RectangularRegion p_r1,
            in template (value) RectangularRegion p_r2
        ) return boolean {
garciay's avatar
garciay committed
            return not (    valueof(p_r2).northwest.longitude > valueof(p_r1).southeast.longitude
                or valueof(p_r2).southeast.longitude < valueof(p_r1).northwest.longitude
                or valueof(p_r2).southeast.latitude  > valueof(p_r1).northwest.latitude
                or valueof(p_r2).northwest.latitude  < valueof(p_r1).southeast.latitude);
        } // End of function f_isRectangularRegionsIntersected
filatov's avatar
filatov committed
        
        function f_isContinuousRectangularRegions(in template (value) RectangularRegions regions
        ) return boolean {
filatov's avatar
filatov committed
            // TODO: call external function
filatov's avatar
filatov committed
            return true;
        } // End of function f_isRectangularRegionsIntersected
        
        /**
        * @desc Check if a polygonal regin is inside another one
        * @param p_parent  The main polygonal region
        * @param p_region  The polygonal region to be included
        * @return true on success, false otherwise
        * @verdict Unchanged
        */
        function f_isRectangularRegionsInside(
            in template (value) RectangularRegions p_parent,
            in template (value) RectangularRegions p_region
        ) return boolean {
            // TODO: convert rectangular regions to polygons and check polygons
filatov's avatar
filatov committed
            return true;
        } // End of function f_isRectangularRegionsInside
        * @desc    Check that given polygon doesn't have neither self-intersections nor holes.
        * @param   p_region   Polygonal Region
        * @return  true on success, false otherwise
        * @verdict Unchanged
        */
        function f_isValidPolygonalRegion(
            in template (value) PolygonalRegion p_region
filatov's avatar
filatov committed
        ) return boolean {
            // Sanity check
            if (not isbound(p_region) or (lengthof(p_region) == 0)) {
                return false;
            }
            
garciay's avatar
garciay committed
            return fx_isValidPolygonalRegion(valueof(p_region));
        } // End of function f_isValidPolygonalRegion
        * @desc Check if a polygonal regin is inside another one
        * @param p_parent  The main polygonal region
        * @param p_region  The polygonal region to be included
        * @return true on success, false otherwise
        * @verdict Unchanged
        */
        function f_isPolygonalRegionInside(
            in template (value) PolygonalRegion p_parent,
            in template (value) PolygonalRegion p_region
filatov's avatar
filatov committed
        ) return boolean {
            // Sanity check
            if (not isbound(p_parent) or not isbound(p_region) or (lengthof(p_parent) == 0) or (lengthof(p_region) == 0)) {
                return false;
            }
            
            return fx_isPolygonalRegionInside(valueof(p_parent), valueof(p_region));
        } // End of function f_isPolygonalRegionInside
garciay's avatar
garciay committed
        
        * @desc
        */
        function f_isIdentifiedRegionInside(
            in template (value) UInt16 p_parent,
            in template (value) UInt16 p_region
        ) return boolean {
garciay's avatar
garciay committed
            return valueof(p_parent) == valueof(p_region);
        } // End of function f_isIdentifiedRegionInside
garciay's avatar
garciay committed
        
        * @desc Check that the location is inside a region
        * @param p_region      The region to consider
        * @param p_location    The device location
        * @return true on success, false otherwise
        * @verdict Unchanged
        */
        function f_isLocationInsideRegion(
            in template (value) GeographicRegion p_region,
            in template (value) ThreeDLocation p_location
        ) return boolean {
            var boolean v_ret := false;
            select (p_region.region_type) {
                case (e_none) {
                    v_ret := true;
                }
                case (e_circle) {
                    v_ret := f_isLocationInsideCircularRegion(p_region.region.circular_region, p_location);
                case (e_rectangle) {
                    v_ret := f_isLocationInsideRectangularRegion(p_region.region.rectangular_region, p_location);
                case (e_polygon) {
                    v_ret := f_isLocationInsidePolygonalRegion(p_region.region.polygonal_region, p_location);
                case (e_id) {
                    v_ret := f_isLocationInsideIdentifiedRegion(p_region.region.id_region, p_location);
                case else {
                    v_ret := f_isLocationInsideOtherRegion(p_region.region.other_region, p_location);