Skip to content
LibItsSecurity_Functions.ttcn 112 KiB
Newer Older
                                                               in template (value) EccP256CurvePoint 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 EtsiTs103097Certificate payload to be verified
                /* FIXME To be reviewed v_toBeSignedCertificate := m_toBeSignedCertificate(p_certificateToBeVerified);
                toBeVerifiedData := bit2oct(encvalue(v_toBeSignedCertificate));
garciay's avatar
garciay committed
                               
                // Build the signature
                v_signature :=
                    valueof(p_certificateToBeVerified.signature_.ecdsaNistP256Signature.rSig) &
                    valueof(p_certificateToBeVerified.signature_.ecdsaNistP256Signature.sSig);
garciay's avatar
garciay committed
                log("toBeVerifiedData: ", toBeVerifiedData);
                log("v_signature     : ", v_signature);
                log("EcdsaP256Signature       :", p_publicKey);
                // Verify the certificate
                v_result := f_verifyWithEcdsaNistp256WithSha256(
                    toBeVerifiedData,
                    v_signature,
                    valueof(p_publicKey.uncompressedP256.x),
                    valueof(p_publicKey.uncompressedP256.y)
                );*/
                return v_result;
            } // End of finction f_verifyCertificateSignatureWithPublicKey
            * @desc Verify the signature of the provided secured message
            * @param p_certificateToBeVerified EtsiTs103097Certificate to be verified
            * @param p_issuingCertificate      Issuing certificate
            * @return true on success, false otherwise
            * @verdict
            */
            function f_verifyCertificateSignatureWithIssuingCertificate(
                                                                        in template (value) EtsiTs103097Certificate p_certificateToBeVerified,
                                                                        in template (value) EtsiTs103097Certificate p_issuingCertificate
                /* FIXME To be reviewed for (var integer 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,
                            valueof(p_issuingCertificate.subject_attributes[v_counter].attribute.key));
                }*/ // End of 'for' statement
            } // 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     EtsiTs103097Certificate to be used to verify the message
            * @return true on success, false otherwise
            * @verdict
            */
            function f_verifyGnSecuredMessageSignatureWithPublicKey(
                                                                    in template (value) Ieee1609Dot2Data p_securedMessage,
                                                                    in template (value) EccP256CurvePoint p_publicKey
            ) return boolean {
                
                // Local variables
                var octetstring v_secPayload;
                var octetstring v_signedData;
filatov's avatar
filatov committed
// FIXME (DF) UNUSED
//                var Oct32 v_hash;
                var integer v_counter;
                var boolean v_result := false;
                var template (value) ToBeSignedData v_toBeSignedData;
//                log(">>> f_verifyGnSecuredMessageSignatureWithPublicKey: p_securedMessage= ", p_securedMessage);
//                log(">>> f_verifyGnSecuredMessageSignatureWithPublicKey: p_publicKey= ", p_publicKey);
                // Create Ieee1609Dot2Data payload to be signed
                /* FIXME To be reviewed v_toBeSignedData := m_toBeSignedSecuredMessage(
                    valueof(p_securedMessage.header_fields),
                    valueof(p_securedMessage.payload_field),
                log("f_verifyGnSecuredMessageSignatureWithPublicKey: v_toBeSignedData=", v_toBeSignedData);
                v_secPayload := bit2oct(encvalue(v_toBeSignedData));
                log("f_verifyGnSecuredMessageSignatureWithPublicKey: v_secPayload=", v_secPayload);
                
                // Verify payload
                for (v_counter := 0; v_counter < lengthof(p_securedMessage.trailer_fields); v_counter := v_counter + 1) {
                    var Ieee1609Dot2Data 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_.ecdsaNistP256Signature.rSig &
                        v_securedMessage.trailer_fields[v_counter].trailerField.signature_.ecdsaNistP256Signature.sSig;
                        log("f_verifyGnSecuredMessageSignatureWithPublicKey: v_signedData=", v_signedData);
                        v_result := f_verifyWithEcdsaNistp256WithSha256(
garciay's avatar
garciay committed
                            v_secPayload, 
                            v_signedData,
                            valueof(p_publicKey.uncompressedP256.x),
                            valueof(p_publicKey.uncompressedP256.y)
garciay's avatar
garciay committed
                        break;
                }*/ // End of 'for' statement
                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     EtsiTs103097Certificate to be used to verify the message
            * @return true on success, false otherwise
            * @verdict
            */
            function f_verifyGnSecuredMessageSignatureWithCertificate(
                                                                      in template (value) Ieee1609Dot2Data p_securedMessage,
                                                                      in template (value) EtsiTs103097Certificate p_certificate
                /* FIXME To be reviewed for (var integer 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);
garciay's avatar
garciay committed
                    if (v_subjectAttribute.type_ == e_verification_key) {
                        return f_verifyGnSecuredMessageSignatureWithPublicKey(
                            p_securedMessage,
                            valueof(p_certificate.subject_attributes[v_counter].attribute.key));
                }*/ // End of 'for' statement
            } // End of function f_verifyGnSecuredOtherMessageWithDeviceCertificate
        } // End of group deviceSignatureHelpers
filatov's avatar
filatov committed
        group messageGetters {
            * @desc    return Ieee1609Dot2Data header field of given type or null if none
            * @param   p_msg the Ieee1609Dot2Data
            * @param   p_type header field type
            * @return  HeaderInfo of given type if any or null
            function f_getMsgHeaderField(
                                         in  template(omit) Ieee1609Dot2Data p_securedMessage,
                                         in  HeaderInfo p_headerInfo,
                                         out HeaderInfo p_return
garciay's avatar
garciay committed
                /*Spirent splitted*/
                var integer v_length;
                var Ieee1609Dot2Data v_securedMessage;
garciay's avatar
garciay committed
                if (not isvalue(p_securedMessage)) {
                    testcase.stop(__SCOPE__ & " can not handle omitted secured message values");
                }
                v_securedMessage := valueof(p_securedMessage);
garciay's avatar
garciay committed
                /*Spirent replaced p_securedMessage with v_securedMessage*/
                /* FIXME To be reviewed tv_length := lengthof(v_securedMessage.header_fields);
                for (var integer i := 0; i < v_length; i := i + 1) {
garciay's avatar
garciay committed
                    if (v_securedMessage.header_fields[i].type_ == p_headerFieldType) {
                        p_return := v_securedMessage.header_fields[i];
                        return true;
                
                log("f_getMsgHeaderField: return false");
            * @desc    return SignerIdentifier Ieee1609Dot2Data field
            function f_getMsgSignerIdentifier (
                                         in template(omit) Ieee1609Dot2Data p_securedMessage,
                                         out SignerIdentifier p_signerIdentifier
                var HeaderInfo v_hf;
                /* FIXME To be reviewed tif (f_getMsgHeaderField(p_securedMessage, e_signer_info, v_hf) == true) {
                    if (isbound(v_hf.headerField.signer)) {
                        p_signerIdentifier := v_hf.headerField.signer;
                log("f_getMsgSignerIdentifier: return false");
garciay's avatar
garciay committed
            
filatov's avatar
filatov committed
        }// End of group messageGetters
        
        group certificateGetters {
             * @desc Set the generation location as defined in Draft ETSI TS 103 097 V1.1.14 Clause 7.2 Security profile for DENMs
             * @param p_latitude    The latitude value of the ITS-S position
             * @param p_longitude   The longitude value of the ITS-S position
             * @param p_elevation   The elevation value of the ITS-S position
             * @verdict Unchanged
             */
            function f_setGenerationLocation(
                                             in SecLatitude p_latitude,
                                             in SecLongitude p_longitude,
                                             in SecElevation p_elevation := 0
            ) 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(
garciay's avatar
garciay committed
                                        in charstring p_configId
            ) runs on ItsSecurityBaseComponent return boolean {
filatov's avatar
filatov committed
// FIXME (DF) UNUSED
//                var boolean v_result;
                
                // Setup certificates memory cache
                /* FIXME To be reviewed if (fx_loadCertificates(PX_CERTIFICATE_POOL_PATH, p_configId) == true) {
                    // Setup security component variables
                    if(f_readCertificate(cc_taCert_A, vc_atCertificate)) {
                        if(f_readCertificate(oct2str(vc_atCertificate.cracaId), vc_aaCertificate)) {
                            if(f_readSigningKey(cc_taCert_A, vc_signingPrivateKey)) {
                                f_readEncryptingKey(cc_taCert_A, vc_encryptPrivateKey);
                                return true;
                            }
                            log("f_loadCertificates: Failed to load signing key for ", cc_taCert_A);
                        }else{
                            log("f_loadCertificates: Failed to load AA certificate for ", cc_taCert_A);
                        }
                    }else{
                        log("f_loadCertificates: Failed to load AT certificate for ", cc_taCert_A);
                    }
                }else{
                    log("f_loadCertificates: Failed to load certificates from ", PX_CERTIFICATE_POOL_PATH);
                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(
garciay's avatar
garciay committed
                                       in charstring p_certificateId,
                                       out EtsiTs103097Certificate p_certificate
            ) runs on ItsSecurityBaseComponent return boolean {
                var octetstring v_certificate;
                
                if (fx_readCertificate(p_certificateId, v_certificate) == true) {
garciay's avatar
garciay committed
                    var bitstring v_oct2bit;
                    var integer v_result;
                    
                    v_oct2bit := oct2bit(v_certificate);
                    v_result := decvalue(v_oct2bit, p_certificate);
                    if (v_result == 0) {
                        return true;
                    }
                }
                
                log("f_readCertificate: Failed to retrieve ", p_certificateId);
                return false;
            } // End of function f_readCertificate

            /**
            * @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_getCertificateDigest(
                                       in charstring p_certificateId,
                                       out HashedId8 p_digest
            ) runs on ItsSecurityBaseComponent return boolean {
                if( not fx_readCertificateDigest(p_certificateId, p_digest)){
                    log("f_getCertificateDigest: Failed to retrieve digest for ", p_certificateId);
                    return false;
                }
                return true;
            } // End of function f_getCertificateDigest
            * @desc    Read the signing private key for the specified certificate
            * @param   p_keysId            the keys identifier
            * @param   p_signingPrivateKey the signing private key
            * @return  true on success, false otherwise
            */
            function f_readSigningKey(
                                       in charstring p_keysId,
                                       out Oct32 p_signingPrivateKey
            ) runs on ItsSecurityBaseComponent return boolean {
                return fx_readSigningKey(p_keysId, p_signingPrivateKey);
            } // End of function f_readSigningKey
            
            /**
            * @desc    Read the encrypting private keys for the specified certificate
            * @param   p_keysId            the keys identifier
            * @param   p_encryptPrivateKey the encrypt private key
            * @return  true on success, false otherwise
            */
            function f_readEncryptingKey(
garciay's avatar
garciay committed
                                         in charstring p_keysId,
                                         out Oct32 p_encryptPrivateKey
            ) runs on ItsSecurityBaseComponent return boolean {
                return fx_readEncryptingKey(p_keysId, p_encryptPrivateKey);
            } // End of function f_readEncryptingKey
            function f_getCertificateValidityRestriction(
                                                         in template (value) EtsiTs103097Certificate p_cert,
                                                         out ValidityPeriod p_return
                /* FIXME To be reviewed tfor (var integer i := 0; i < lengthof(p_cert.validity_restrictions); i := i + 1) {
//FIXME RGY Titan doesn't support dot notation after valueof at the moment
//                    if (valueof(p_cert).validity_restrictions[i].type_ == p_type) {
//                        p_return := valueof(p_cert).validity_restrictions[i];
                    if (valueof(p_cert.validity_restrictions[i].type_) == p_type) {
                        p_return := valueof(p_cert.validity_restrictions[i]);
filatov's avatar
filatov committed
                    }
garciay's avatar
garciay committed
                } // End of 'for' statement
                
                log("f_getCertificateValidityRestriction: Failed to retrieve ", p_type);*/
            } // End of function f_getCertificateValidityRestriction
filatov's avatar
filatov committed
            
            function f_getCertificateSignerIdentifier(
                                                in template (value) EtsiTs103097Certificate p_cert,
                                                out SignerIdentifier p_si
                /* FIXME To be reviewed tif (isbound(valueof(p_cert.signer_info))) {
                    p_si := valueof(p_cert.signer_info);
                log("f_getCertificateSignerIdentifier: Failed to retrieve ");
filatov's avatar
filatov committed
            }
            
            function f_getCertificateSubjectAttribute(
                                                      in template (value) EtsiTs103097Certificate p_cert/* FIXME To be reviewed,
                                                      out SubjectAttribute p_return*/
            ) return boolean {
                /* FIXME To be reviewed tfor (var integer i := 0; i < lengthof(p_cert.subject_attributes); i := i + 1) {
//FIXME RGY Titan doesn't support dot notation after valueof at the moment
//                    if (valueof(p_cert).subject_attributes[i].type_ == p_type) {
//                        p_return := valueof(p_cert).subject_attributes[i];
                    if (valueof(p_cert.subject_attributes[i].type_) == p_type) {
                        p_return := valueof(p_cert.subject_attributes[i]);
                log("f_getCertificateSubjectAttribute: Failed to retrieve ", p_type);*/
filatov's avatar
filatov committed
        }// End of group certificateGetters
garciay's avatar
garciay committed
        group certificatesCaching {
            
            function f_createCertificatesCaching(
                                                 in SequenceOfCertificate p_certificates, 
garciay's avatar
garciay committed
                                                 out CertificatesCaching p_certificatesCaching
            ) return boolean {
                p_certificatesCaching := { };
                for (var integer v_counter := 0; v_counter < lengthof(p_certificates); v_counter := v_counter + 1) {
                    var CertificatesCachingItem v_item;
                    v_item.certificate := p_certificates[v_counter];
                    v_item.hashedId8 := f_calculateDigestFromCertificate(v_item.certificate);
                    p_certificatesCaching[v_counter] := v_item;
                } // End of 'for' statement
                
                return true;
            }
            
            function f_getCertificateFromCaching(
                                                 in CertificatesCaching p_certificatesCaching, 
                                                 in HashedId8 p_hashedId8, 
                                                 out EtsiTs103097Certificate p_certificate
garciay's avatar
garciay committed
            ) return boolean {
                for (var integer v_counter := 0; v_counter < lengthof(p_certificatesCaching); v_counter := v_counter + 1) { 
                    if (match(p_certificatesCaching[v_counter].hashedId8, p_hashedId8) == true) {
                        p_certificate := p_certificatesCaching[v_counter].certificate;
                        return true;
                    }
                } // End of 'for' statement
                
                return false;
            }
            
            function f_getCertificatesCachingItem(
                                                  in CertificatesCaching p_certificatesCaching, 
                                                  in UInt8 p_index, 
                                                  out EtsiTs103097Certificate p_certificate
garciay's avatar
garciay committed
            ) return boolean {
                if (lengthof(p_certificatesCaching) < p_index) {
                    p_certificate := p_certificatesCaching[p_index].certificate;
                    return true;
                }
                
                return false;
            }
            
            function f_getCertificatesCachingItemSize(
                                                      in CertificatesCaching p_certificatesCaching
            ) return UInt8 {
                return lengthof(p_certificatesCaching);
            }
            
        }// End of group certificatesCaching
        
        
    } // 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 specified certificate digest
            * @param   p_certificateId the certificate identifier
            * @param   p_digest   the expected certificate
            * @return  true on success, false otherwise
            */
            external function fx_readCertificateDigest(in charstring p_certificateId, out HashedId8 p_digest) return boolean;
            * @desc    Read the private keys for the specified certificate
            * @param   p_keysId            the keys identifier
            * @param   p_signingPrivateKey the signing private key
            * @return  true on success, false otherwise
            */

            external function fx_readSigningKey(in charstring p_keysId, out Oct32 p_signingPrivateKey) return boolean;

            /**
            * @desc    Read the private keys for the specified certificate
            * @param   p_keysId            the keys identifier
            * @param   p_encryptPrivateKey the encrypt private key
            * @return  true on success, false otherwise
            */

            external function fx_readEncryptingKey(in charstring p_keysId, out Oct32 p_encryptingPrivateKey) 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 region 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
            */
            external function fx_isLocationInsideRectangularRegion(in SequenceOfRectangularRegion 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;
garciay's avatar
garciay committed
            /**
            * @desc Check if the location is inside an undefined region
            * @param p_region      The identified region to consider
            * @param p_location    The device location
            * @return true on success, false otherwise
            * @verdict Unchanged
            */
            external function fx_isLocationInsideOtherRegion(in octetstring p_region, in ThreeDLocation p_location) return boolean; 
garciay's avatar
garciay committed
            
            /**
             * @desc    Check that p_circular_region_1 circular region is included into p_circular_region_2 circular region
             * @param   p_circular_region_1    Circular region 1
             * @param   p_circular_region_2    Circular region 2
             *
             * @return  true on success, false otherwise
             */
            external function fx_areCirclesInside(in CircularRegion p_circular_region_1, in CircularRegion p_circular_region_2) return boolean;
            
            /**
             * @desc    Check that p_rectanglar_region_1 rectangular region is included into p_rectanglar_region_2 rectangular region
             * @param   p_rectanglar_region_1    Rectangular region 1
             * @param   p_rectanglar_region_2    Rectangular region 2
             *
             * @return  true on success, false otherwise
             */
            external function fx_areRectanglesInside(in SequenceOfRectangularRegion p_rectanglar_region_1, in SequenceOfRectangularRegion p_rectanglar_region_2) return boolean;
garciay's avatar
garciay committed
            
            /**
             * @desc    Check that p_polygonal_region_1 polygonal region is included into p_polygonal_region_2 polygonal region
             * @param   p_polygonal_region_1    Polygonal region 1
             * @param   p_polygonal_region_2    Polygonal region 2
             *
             * @return  true on success, false otherwise
             */
            external function fx_arePolygonsInside(in PolygonalRegion p_polygonal_region_1, in PolygonalRegion p_polygonal_region_2) 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 {
        
garciay's avatar
garciay committed
        function f_checkRegionValidityRestiction(
                                                 in EtsiTs103097Certificate p_cert, 
                                                 in EtsiTs103097Certificate p_cert_issuer
garciay's avatar
garciay committed
        ) return boolean {
            var ValidityPeriod v_cert_region, v_cert_issuer_region;
garciay's avatar
garciay committed
            var boolean v_cert_issuer_region_result;
            
            /* FIXME To be reviewed v_cert_issuer_region_result := f_getCertificateValidityRestriction(p_cert_issuer, e_region, v_cert_issuer_region);
garciay's avatar
garciay committed
            if (f_getCertificateValidityRestriction(p_cert, e_region, v_cert_region) == false) {
                if (v_cert_issuer_region_result == true) {
garciay's avatar
garciay committed
                    if (v_cert_issuer_region.validity.region.region_type != e_none) {
garciay's avatar
garciay committed
                        return false;
                    }
                }
            } else if (
                        (v_cert_issuer_region_result == true) and 
garciay's avatar
garciay committed
                        (v_cert_issuer_region.validity.region.region_type != e_none)
garciay's avatar
garciay committed
            ) {
garciay's avatar
garciay committed
                if (v_cert_region.validity.region.region_type == e_circle) {
                    if (v_cert_issuer_region.validity.region.region_type == e_circle) {
garciay's avatar
garciay committed
                        // Check v_cert_region 'circle' is inside v_cert_issuer_region 'circle'
                        if (f_areCirclesInside(v_cert_region.validity.region.region.circular_region, v_cert_issuer_region.validity.region.region.circular_region) == false) {
                            log("*** " & testcasename() & ": FAIL: Issuer and issuing certificates circle area does not match ***");
                            return false;
                        }
                    }
garciay's avatar
garciay committed
                } else if (v_cert_region.validity.region.region_type == e_rectangle) {
                    if (v_cert_issuer_region.validity.region.region_type == e_rectangle) {
garciay's avatar
garciay committed
                        // Check v_cert_region 'rectangle' is inside v_cert_issuer_region 'rectangle'
                        if (f_areRectanglesInside(v_cert_region.validity.region.region.rectangular_region, v_cert_issuer_region.validity.region.region.rectangular_region) == false) {
                            log("*** " & testcasename() & ": FAIL: Issuer and issuing certificates rectangle area does not match ***");
                            return false;
                        }
                    }
garciay's avatar
garciay committed
                } else if (v_cert_region.validity.region.region_type == e_polygon) {
                    if (v_cert_issuer_region.validity.region.region_type == e_polygon) {
garciay's avatar
garciay committed
                        // Check v_cert_region 'polygon' is inside v_cert_issuer_region 'polygon'
                        if (f_arePolygonsInside(v_cert_region.validity.region.region.polygonal_region, v_cert_issuer_region.validity.region.region.polygonal_region) == false) {
                            log("*** " & testcasename() & ": FAIL: Issuer and issuing certificates polygon area does not match ***");
                            return false;
                        }
                    }
garciay's avatar
garciay committed
                } else if (v_cert_region.validity.region.region_type == e_id) {
garciay's avatar
garciay committed
                    // Check id_region
                    if (not match (v_cert_region.validity.region, mw_geographicRegion_identified(mw_identifiedRegion_iso3166_any))) { 
                        log("*** " & testcasename() & ": FAIL: Identified region is not conformed to ISO 3166-1 ***");
                        return false;
                    }
                    if (not match (v_cert_region.validity.region, mw_geographicRegion_identified(mw_identifiedRegion_un_stats_any))) {
                        log("*** " & testcasename() & ": FAIL: Identified region is not conformed to United Nations Statistics Division ***");
                        return false;
                    }
                    // Check region_dictionary
                    if (not match (v_cert_region.validity.region.region.id_region.region_dictionary, v_cert_issuer_region.validity.region.region.id_region.region_dictionary)) {
                        log("*** " & testcasename() & ": FAIL: Issuer and issuing 'region_dictionary' field does not match ***");
                        return false;
                    }
                    // Check region_identifier
                    if (not match (v_cert_region.validity.region.region.id_region.region_identifier, v_cert_issuer_region.validity.region.region.id_region.region_identifier)) {
                        log("*** " & testcasename() & ": FAIL: Issuer and issuing 'region_identifier' field does not match ***");
                        return false;
                    }
                    // Check local_region
                    if (
                        (not match (v_cert_issuer_region.validity.region.region.id_region.local_region, v_cert_region.validity.region.region.id_region.local_region)) or 
                        (not match (v_cert_issuer_region.validity.region.region.id_region.local_region, 0))
                    ) {
                        log("*** " & testcasename() & ": FAIL: Issuer and issuing 'local_region' field does not match ***");
                        return false;
garciay's avatar
garciay committed
                    }
                }
garciay's avatar
garciay committed
            
            return true;
        } // End of function f_checkRegionValidityRestiction
        
filatov's avatar
filatov committed
        /**
garciay's avatar
garciay committed
         * @desc    Check that p_circular_region_1 circular region is included into p_circular_region_2 circular region
         * @param   p_circular_region_1    Circular region 1
         * @param   p_circular_region_2    Circular region 2
         *
         * @return  true on success, false otherwise
         */
        function f_areCirclesInside(
                                    in CircularRegion p_circular_region_1, 
                                    in CircularRegion p_circular_region_2
        ) return boolean {
            return fx_areCirclesInside(p_circular_region_1, p_circular_region_2);
        }
        
        /**
         * @desc    Check that p_rectanglar_region_1 rectangular region is included into p_rectanglar_region_2 rectangular region
         * @param   p_rectanglar_region_1    Rectangular region 1
         * @param   p_rectanglar_region_2    Rectangular region 2
         *
         * @return  true on success, false otherwise
         */
        function f_areRectanglesInside(
                                       in SequenceOfRectangularRegion p_rectanglar_region_1, 
                                       in SequenceOfRectangularRegion p_rectanglar_region_2
garciay's avatar
garciay committed
        ) return boolean {
            return fx_areRectanglesInside(p_rectanglar_region_1, p_rectanglar_region_2);
        }
        
        /**
         * @desc    Check that p_polygonal_region_1 polygonal region is included into p_polygonal_region_2 polygonal region
         * @param   p_polygonal_region_1    Polygonal region 1
         * @param   p_polygonal_region_2    Polygonal region 2
         *
         * @return  true on success, false otherwise
         */
        function f_arePolygonsInside(
                                     in PolygonalRegion p_polygonal_region_1, 
                                     in PolygonalRegion p_polygonal_region_2
        ) return boolean {
            return fx_arePolygonsInside(p_polygonal_region_1, p_polygonal_region_2);
        }
        
        /**
         * @desc    Check that given location is valid
         * @param   p_location    location to be checked
         * @return  true on success, false otherwise
         */
        function f_isValidTwoDLocation(
garciay's avatar
garciay committed
                                       in template (value) TwoDLocation p_location
filatov's avatar
filatov committed
        ) return boolean {
//FIXME RGY Titan doesn't support dot notation after valueof at the moment
//                (valueof(p_location).longitude != c_maxLongitude + 1) and
//                (valueof(p_location).latitude != c_maxLatitude + 1);
                (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
        /**
garciay's avatar
garciay committed
         * @desc    Check that two given rectanlular regions are intersected
         *          Note: Regions must be normalized(northWest.latitude >= southEast.latitude)
garciay's avatar
garciay committed
         * @param   p_r1    Region 1
         * @param   p_r2    Region 2
         *
         * @return  true on success, false otherwise
         */
        function f_isRectangularRegionsIntersected(
garciay's avatar
garciay committed
                                                   in template (value) RectangularRegion p_r1,
                                                   in template (value) RectangularRegion p_r2
        ) return boolean {
garciay's avatar
garciay committed
            return not (
//FIXME RGY Titan doesn't support dot notation after valueof at the moment
//                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
                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)
garciay's avatar
garciay committed
            );
        } // End of function f_isRectangularRegionsIntersected
filatov's avatar
filatov committed
        
garciay's avatar
garciay committed
        function f_isContinuousRectangularRegions(
                                                  in template (value) SequenceOfRectangularRegion p_region
filatov's avatar
filatov committed
        ) return boolean {
            var integer v_i, v_j;
            var boolean v_found;
            
            for (v_i := 0; v_i < lengthof(p_region); v_i := v_i + 1) {
                var PolygonalRegion v_region_base;
                f_convertRectangularRegionIntoPolygonalRegion(valueof(p_region[v_i]), v_region_base);
                v_found := false;
                for (v_j := 0; v_j < lengthof(p_region); v_j := v_j + 1) {
                    if (v_j != v_i) {
                        var PolygonalRegion v_region;
                        f_convertRectangularRegionIntoPolygonalRegion(valueof(p_region[v_j]), v_region);
                        if (f_isPolygonalRegionInside(v_region, v_region_base) == true) {
                            v_found := true;
                        }
                    }
                } // End of 'for' statement
                if (v_found == false) {
                    return false;
                }
            } // End of 'for' statement
            
filatov's avatar
filatov committed
            return true;
        } // End of function f_isContinuousRectangularRegions
         * @desc Check if a polygonal region is inside another one
garciay's avatar
garciay committed
         * @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) SequenceOfRectangularRegion p_parent,
                                              in template (value) SequenceOfRectangularRegion p_region
        ) return boolean {
            var integer v_i, v_j;
            
            for (v_i := 0; v_i < lengthof(p_parent); v_i := v_i + 1) {
                var PolygonalRegion v_region_parent, v_region;
                f_convertRectangularRegionIntoPolygonalRegion(valueof(p_parent[v_i]), v_region_parent);
                for (v_j := 0; v_j < lengthof(p_parent); v_j := v_j + 1) {
                    f_convertRectangularRegionIntoPolygonalRegion(valueof(p_region[v_j]), v_region);
                    if (f_isPolygonalRegionInside(v_region, v_region_parent) == true) {
                        return true;
                    }
                } // End of 'for' statement
            } // End of 'for' statement
            
            return false;
        } // End of function f_isRectangularRegionsInside
        /**
         * @desc Convert a rectangular region into a polygonal region
         * @param p_region The rectangular regions to convert
         * @return 
         * @verdict 
         */
        function f_convertRectangularRegionIntoPolygonalRegion(
                                                               in template (value) RectangularRegion p_rectangular_region,
                                                               out PolygonalRegion p_region
filatov's avatar
filatov committed
// FIXME (DF) UNUSED
//            var integer v_counter := 0;
            
            // Convert rectangular regions to polygons and check polygons
            p_region[0] := valueof(p_rectangular_region.northWest);
                valueof(p_rectangular_region.northWest.latitude) + valueof(p_rectangular_region.southEast.latitude),
                valueof(p_rectangular_region.northWest.longitude)
            p_region[2] := valueof(p_rectangular_region.southEast);
                valueof(p_rectangular_region.northWest.latitude),
                valueof(p_rectangular_region.northWest.longitude) + valueof(p_rectangular_region.southEast.longitude) 
            };
            log("f_convertRectangularRegionIntoPolygonalRegion: DEBUG: Northwest location is invalid in rect ", p_region);
            
            return true;
        } // End of function 
        
garciay's avatar
garciay committed
         * @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(
garciay's avatar
garciay committed
                                          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 region is inside another one
garciay's avatar
garciay committed
         * @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(
garciay's avatar
garciay committed
                                           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(
garciay's avatar
garciay committed
                                            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(
garciay's avatar
garciay committed
                                          in template (value) GeographicRegion p_region,
                                          in template (value) ThreeDLocation p_location
        ) return boolean {
            var boolean v_ret := false;
//FIXME RGY valeuof is missing: argument of select case is Expression (see $19.3.1)
//            select (p_region.region_type) {
            if (ischosen(p_region.circularRegion)) {
                v_ret := f_isLocationInsideCircularRegion(valueof(p_region.circularRegion), p_location);
            } else if (ischosen(p_region.rectangularRegion)) {
                v_ret := f_isLocationInsideRectangularRegion(valueof(p_region.rectangularRegion), p_location);
            } else if (ischosen(p_region.polygonalRegion)) {
                v_ret := f_isLocationInsidePolygonalRegion(valueof(p_region.polygonalRegion), p_location);
            } else if (ischosen(p_region.identifiedRegion)) {
                for (var integer v_i := 0; v_i < lengthof(p_region.identifiedRegion); v_i := v_i + 1) {
                    if (f_isLocationInsideIdentifiedRegion(valueof(p_region.identifiedRegion[v_i]), p_location) == true) {
                        v_ret := true;
                        break;
                    }
                } // End of 'for' statement
        } // End of function f_isLocationInsideRegion
        
        /**
        * @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
        function f_isLocationInsideCircularRegion(
                                                  in template (value) CircularRegion p_region,
                                                  in template (value) ThreeDLocation p_location
        ) return boolean {
            // Sanity check
            if (not isbound(p_region) or not isbound(p_location)) {
                return false;
            }
            
garciay's avatar
garciay committed
            return fx_isLocationInsideCircularRegion(valueof(p_region), valueof(p_location));
        } // End of function f_isLocationInsideCircularRegion
        
        /**
        * @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
        */
        function f_isLocationInsideRectangularRegion(