ucoProject / UCO

This repository is for development of the Unified Cyber Ontology.
Apache License 2.0
79 stars 34 forks source link

cpeid should constrain values through CPE version and "Part" component of Well-Formed Name #626

Open ajnelson-nist opened 2 months ago

ajnelson-nist commented 2 months ago

Background

observable:cpeid is currently (as of UCO 1.3.0) an unconstrained string.

The CPE 2.3 naming specification, NISTIR 7695 provides syntactic constraints for a "Well-Formed Name" (WFN). Some seem appropriate to include in UCO:

Prior versions of the CPE specification(s) are currently available here, but they are not referenced further in this proposal.

Requirements

Requirement 1

UCO must constrain CPEs in cpeid to be specified as Well-Formed-Names of the current version, 2.3.

(Aside: This intentionally excludes URI forms from being used in cpeid.)

Requirement 2

UCO must constrain CPEs for Devices to use an h Part (for hardware devices).

Requirement 3

UCO must constrain CPEs for Software to use an a Part (for applications).

Requirement 4

UCO must constrain CPEs for OperatingSystem to use an o Part (for operating systems).

Non-Requirements

No further constraints on CPE WFN parts are suggested in this proposal. Handling the entire grammar, including escape sequences, makes even counting the number of fields by colon-delimiting likely too cumbersome for a single regular expression to be beneficial.

Risk / Benefit analysis

Benefits

Risks

Competencies demonstrated

Competency 1

Error detection: A tablet device is given an operating system CPE.

{
    "@context": {
        "kb": "http://example.org/kb/",
        "core": "https://ontology.unifiedcyberontology.org/uco/core/",
        "observable": "https://ontology.unifiedcyberontology.org/uco/observable/"
    },
    "@graph": [
        {
            "@id": "kb:Device-3b8fde6f-0f0b-4472-b9c8-31380eb80dc3",
            "@type": "observable:Tablet",
            "core:hasFacet": {
                "@id": "kb:DeviceFacet-4a1cdff8-be81-46e3-8502-0f488d353ca0",
                "@type": "observable:DeviceFacet",
                "observable:cpeid": "cpe:2.3:o:exampleco:exampletabletos:-:*:*:*:*:*:*:*"
            }
        }
    ]
}

Competency Question 1.1

Is this a valid usage of that CPE WFN?

Result 1.1

No.

The WFN having an o value implies the associated item (the observable:Tablet) should be an operating system. But, it is a device (i.e., an instance of an observable:Device subclass).

If that WFN is desired to appear in the graph, the operating system of the device should be modeled as a separate object and tied to the device with an observable:ObservableRelationship.

Solution suggestion

(I am fine with my examples being transcribed and credited.)

observable:DeviceFacet
    sh:property [
        sh:message "In UCO 2.0.0, cpeid in DeviceFacet will be constrained to be a CPE version 2.3 hardware name."@en ;
        sh:path observable:cpeid ;
        sh:pattern "^cpe:2.3:h:.+" ;
        sh:severity sh:Warning ;
    ] ;
    .
observable:OperatingSystemFacet
    sh:property [
        sh:maxCount "0"^^xsd:integer ;
        sh:message "observable:cpeid should appear on a SoftwareFacet instead of an OperatingSystemFacet."@en ;
        sh:path observable:cpeid ;
        sh:severity sh:Warning ;
    ] ;
    .
# NOTE: The PropertyShape is not on a Facet subclass.
observable:OperatingSystem
    sh:property [
        sh:message "In UCO 2.0.0, cpeid in any Facet attached to an OperatingSystem will be constrained to be a CPE version 2.3 operating system name."@en ;
        sh:path (
            core:hasFacet
            observable:cpeid
        ) ;
        sh:pattern "^cpe:2.3:o:.+" ;
        sh:severity sh:Warning ;
    ] ;
    .

Aside on unpursued option

A "more correct" constraining would instead apply the o pattern only on a SoftwareFacet, which can be done in a few ways. Unfortunately, each is complex to implement without adding additional single-purpose OWL Classes never really meant for a user to explicitly instantiate, or complex spellings of "if P then Q" using sh:or. Any of these solutions is likely to be unnecessarily challenging to parse to any end user who ultimately put an a where an o should have gone.

For example (and it's hopefully clear why this is not in the pull request): In SHACL, spelling "If P, then Q" when custom classes are not an option needs to be done with the Implication-as-Or's spelling, "p → q ≡ ¬p ∨ q". Hence, the option for representing "IF this SoftwareFacet is a facet of an OperatingSystem object, THEN apply the 'o' CPE pattern constraint" is as follows:

observable:SoftwareFacet
    sh:property [
        sh:message "In UCO 2.0.0, cpeid in a SoftwareFacet attached to an OperatingSystem will be constrained to be a CPE version 2.3 operating system name."@en ;
        sh:or (
            [
                sh:not [
                    sh:property [
                        sh:class observable:OperatingSystem ;
                        sh:path (
                            sh:inversePath [
                                observable:cpeid ;
                            ]
                            sh:inversePath [
                                core:hasFacet
                            ]
                        ) ;
                        # The path starts at the string-literal of the CPE,
                        # then goes back to the SoftwareFacet,
                        # then goes back to the ObservableObject.
                    ] ;
                ] ;
            ]
            [
                sh:pattern "^cpe:2.3:o:.+" ;
            ]
        ) ;
        sh:path observable:cpeid ;
        sh:severity sh:Warning ;
    ] ;
    .

A blanket review of cpeid from observable:OperatingSystem seems more palatable.

Coordination