by J. David Giese on June 22, 2022
An SBOM, or Software Bill of Materials, is a comprehensive list of components, libraries, and dependencies used in a software system. A robust SBOM also includes the software tools used to build and package the software system. It provides transparency about the software's composition, making it easier to track and manage potential vulnerabilities, licensing requirements, and other risks associated with software usage. An SBOM can include information about open-source and commercial components, as well as their respective versions and licensing information.
We suggest including it. The 2022 draft cybersecurity guidance recommends including it, and we’ve had the FDA ask us for it on submissions.
The basic process involves these steps:
We suggest automating as much of this process as possible and even incorporating it into your CI/CD pipeline. For example, if you have Python language dependencies, you can import them from your requirements.txt
file. You can also validate your SBOM as part of a build check.
Usually some components are not tracked anywhere else and need to be manually added.
There are three widely-used SBOM formats:
We recommend the CycloneDX format. It has good tooling support and it’s specification is short and more developer friendly. (Compare it to the SPDX specification.) The CycloneDX format is focused on security use-cases while the SPDX historically focused on open-source license tracking.
The SWID format is a proprietary standard that costs $225 (as of June 2022), so we didn’t consider using it, primarily due to the annoyance of buying and distributing a paid standards PDF.
If you’d like a more in-depth comparison of the formats, the 2021 Survey of Existing SBOM Formats and Standards is a good read.
The short answer is that any other software that’s used in the creation of your software (and thus may introduce vulnerabilities into your software) should be included.
This list may include:
Keeping up with all of these dependencies takes a lot of effort. Thus, given limited resources we suggest focusing on dependencies that are higher risk. How to perform risk analysis on software dependencies is a big topic that we hope to discuss in an upcoming article.
The FDA’s draft guidance recommends that quite a bit of information be included for each component in the SBOM. We feel that, in most cases, it’s not worth the effort to include all of this information. We believe the main way SBOMs will be used is for manufacturers and users of medical devices to monitor when their devices are affected by software vulnerabilities and when they must react. Thus, we suggest including only enough information to accomplish this main use case.
A key part of the SBOM formats is the component identifier. This identifier allows the entries in the SBOM to be checked against various vulnerability databases. Therefore, it’s important that the identifiers be correct, otherwise vulnerability monitoring tools won’t be effective.
So says the NTIA Multistakeholder Process on Software Component Transparency
Framing Working Group, in their 2021 Software Identification Challenges and Guidance.
Perhaps the biggest single challenge to supply chain transparency and the Software Bill of Materials (SBOM) model is identifying software components with sufficient discoverability and uniqueness.
The CycloneDX format supports a few identification mechanisms for identifying components, however, when it comes to identifying known vulnerabilities, the CycloneDX website makes the following comment (emphasis ours):
Identifying known vulnerabilities in components can be achieved through the use of three fields:
cpe
,swid
, andpurl
. Not all fields apply to all types of components. The CPE specification was designed for operating systems, applications, and hardware devices. CPE is maintained by the NVD and has been deprecated [it’s unclear that this is true, see here]. Software ID (SWID) as defined in ISO/IEC 19770-2:2015 is used primarily to identify installed software and is the preferred format of the NVD. Package URL (PURL) standardizes how software package metadata is represented so that packages can universally be located regardless of what vendor, project, or ecosystem the packages belongs.Components that have a cpe, swid, or purl defined can be analyzed for known vulnerabilities.
Guidelines
USE RECOMMENDATION Client or Server Application CPE or SWID Container PURL or SWID Firmware CPE or SWID Library or Framework (package) PURL Library or Framework (non-package) SWID Operating System CPE or SWID Operating System Package PURL or SWID Not all sources of vulnerability intelligence support all three fields. Use of multiple sources may be required to obtain accurate and actionable results.
For language dependencies, often the PURL identification is the only mechanism possible. For example, see this comment by the Python Packaging Working Group:
As you consider SWID in particular, please bear in mind that it only applies to some kinds of software and would need to be supplemented by other identifier schemes to cover other categories; for example, we believe it would not be viable to assign an SWID for every package on PyPI. Please also look into PURL, which attempts to cover that lacuna.
First, familiarize yourself with package URL (purl). See here for some examples.
Then, look up the purl package type that’s applicable to you. Here are all of the types as of 2022:
bitbucket
for Bitbucket-based packagescocoapods
for Cocoapodscargo
for Rustcomposer
for Composer PHP packagesconan
for Conan C/C++ packagesconda
for Conda packagescran
for CRAN R packagesdeb
for Debian, Debian derivatives, and Ubuntu packagesdocker
for Docker imagesgem
for Rubygemsgeneric
for plain, generic packages that do not fit anywhere elsegithub
for Github-based packagesgolang
for Go packageshackage
for Haskell packageshex
for Hex packagesmaven
for Maven JARs and related artifactsnpm
for Node NPM packagesnuget
for NuGet .NET packagesoci
for all artifacts stored in registries that conform to the OCI Distribution Specificationpub
for Dart and Flutter packagespypi
for Python packagesrpm
for RPMsswift
for Swift packagesFor the appropriate URL as specified there.
You can learn more about CPE identifiers here. (If you’re really curious, the full spec is here.)
To search for a CPE identifier, download the archives here and use a text searching tool (like ripgrep) to search through the files. It usually takes some digging.
Note that CPE identifiers are only added for software that has a known vulnerability. Thus, you may occassionaly find a CPE identifier for one version of your component but not for the version you are using. In these cases, we reccomend following the format of the CPE identifier and swapping out the version or year as appropriate.
We’re not sure how to do this.
It would be preferable to have one SBOM to give to your customers and to the FDA. You can use the cyclonedx-cli tool to merge two SBOMs together. Consider using a hierarchical merge when appropriate.
Consider using the free and open-source Dependency Track.
Black Duck is a good paid option to consider as well.
Yes! Here are a few more good reads:
The following examples show how to handle some common situations with SBOM generation when using CycloneDX. Note that the examples are not valid standalone SBOMs since they do not include some mandatory metadata, such as the bomFormat
, speVersion
, or version
.
It’s helpful to include the name and version of your medical device software in the SBOM metadata so that it’s easy to identify which version of your software the SBOM applies to. This information goes inside the metadata.component
field. See here for details. Here’s an example:
{
"metadata": {
"component": {
"type": "application",
"name": "Medical Device Name",
"author": "Medical Device Manufacturer Name",
"version": "1.0.5"
}
},
}
The Visual C++ Redistributable Package is not included in any of the purl types, so we searched the CPE database for it. We found match for the Visual Studio 2017 runtime, but the 2013 runtime was not present. Thus, we copied the CPE identifier for the 2017 runtime and updated the year number as a best guess attempt at identifying this dependency. The “name” field is a best guess based on the CPE string. The “type” is set to “library” despite the fact that the CPE identifier begins with “a” (for application). This is because the runtime isn’t really an application.
{
"components": [
{
"type": "library",
"name": "visual_studio",
"cpe": "cpe:2.3:a:microsoft:visual_studio:2013:-:*:*:*:*:*:*"
}
]
}
None of the purl package types apply to Python itself, thus the CPE identifier was used. A few searches of the CPE database turned up a match. This can be included as a CycloneDX component as follows:
{
"components": [
{
"type": "application",
"name": "python",
"cpe": "cpe:/a:python:python:3.6"
}
]
}
We send out tips about once a month.
Articles about software development, AI, signal and image processing, medical regulations, and other topics of interest to professionals in the medical device software industry.
You may view previous articles here.
The Innolitics team, and experts we collaborate with, write all of our articles.