Embedded HandbookПриложения
Все разделы › XXVI. От макета к изделию
STM32F103 · уровень средний · 13 мин чтения
Открыть в интерактивном справочнике

205б. Лицензии открытого кода и SBOM: что можно взять в прошивку

Раздел 205а собрал на прибор документы по ЕСКД: схему, перечень элементов, спецификацию. В перечне — каждый резистор. А в прошивке того же прибора обычно больше чужого кода, чем своего: CMSIS, HAL, FreeRTOS, файловая система, стек TCP/IP, библиотеки из разделов 42, 42а, 106в и 115г. У каждого куска свой владелец и своя лицензия, и лицензия говорит, на каких условиях этот код можно передавать дальше — в том числе внутри прибора. Здесь — какие лицензии у кода, который уже встречался в справочнике, что в них написано и как составить перечень программных составных частей прошивки (SBOM, software bill of materials) так же строго, как перечень элементов.

Это не юридическая консультация. Раздел пересказывает только то, что написано в самих текстах лицензий, лежащих на диске, с номерами пунктов. Как их применять к конкретному прибору и договору — вопрос к юристу.

Опоры: архив STM32CubeF1 1.8.7 (License.md, Package_license.md, sbom_cdx.json, файлы LICENSE* компонентов, текст SLA0044 в Projects/…/Applications/LICENSE.txt); модули дерева Zephyr (littlefs, nanopb, zcbor, Mbed TLS 3.6) и генератор SPDX Zephyr (scripts/west_commands/zspdx); тексты GPL-2.0, LGPL-3.0 и исключения GCC для библиотеки времени выполнения — из zephyr-sdk-1.0.1. Всё сопоставление — свой генератор sbom205.py; проверка — _verify/lic205c_check.py.

Как это называется в документации

Оригинал Перевод
permissive license разрешительная лицензия: условия — сохранить уведомление, приложить текст
copyleft «копилефт»: производное передаётся на тех же условиях, с исходниками
notice / attribution уведомление об авторском праве и тексте лицензии
object code / binary form объектный код, двоичная форма — в том числе прошитая в прибор
combined work (LGPL) совместное произведение: программа, связанная с библиотекой
runtime library exception исключение для библиотеки времени выполнения (GCC)
SBOM перечень программных составных частей
SPDX license identifier короткое имя лицензии по списку SPDX: MIT, BSD-3-Clause
license expression выражение: Apache-2.0 OR GPL-2.0-or-later
LicenseRef-… своё имя для лицензии, которой нет в списке SPDX

205б.1 Что уже взято и под какими лицензиями

Опыт: дерево исходников прибора собрано из архивов на диске — 12 компонентов, 39 файлов, 2 490 629 байт. Лицензию каждого файла генератор определил по его заголовку, лицензию компонента — по его файлу LICENSE:

Компонент Версия Лицензия Откуда версия
CMSIS-Core 5.4.0 Apache-2.0 ARM.CMSIS.pdsc
CMSIS-Device STM32F1 4.3.5 Apache-2.0 stm32f1xx.h
HAL STM32F1 1.1.10 BSD-3-Clause stm32f1xx_hal.c
FreeRTOS 10.3.1 MIT task.h
USB Device Library ST 2.5.3 SLA0044 Release_Notes.html
FatFs R0.11 своя, одно условие (ff.c); ST, пять условий (ff_gen_drv.c) ff.h
lwIP 2.0.3 BSD-3-Clause init.h
littlefs 2.11 BSD-3-Clause lfs.h
nanopb 0.4.9 Zlib library.json
zcbor 0.9.1 Apache-2.0 VERSION
Mbed TLS 3.6.6 Apache-2.0 OR GPL-2.0-or-later build_info.h
свой код прибора 1.4.2 своя (LicenseRef-Proprietary) —

Дерево прошивки из 12 компонентов и 39 файлов: слева — откуда генератор узнал лицензию файла (метка SPDX у 13 файлов, узнанный текст в заголовке у 13, отсылка к файлу LICENSE у 9, ничего у 4), справа — семьи лицензий: разрешительные Apache-2.0, MIT, BSD-3-Clause, Zlib и FatFs, только для кристаллов ST — SLA0044 и пятипунктная лицензия ST, на выбор — Mbed TLS, и свой код

У HAL и CMSIS-Device в заголовке файла лицензии нет — только фраза, что условия лежат в файле LICENSE компонента. А тот говорит: внутри пакета действуют условия Package_license, вне пакета — BSD-3-Clause (для HAL) и Apache-2.0 (для CMSIS-Device). Package_license.md пакета F1 — это соглашение ST SLA0048, и в его таблице эти компоненты перечислены с BSD-3-Clause и Apache-2.0.

Компонент FatFs показывает, что лицензию надо читать по файлам, а не по названию папки: ff.c от ChaN несёт лицензию с одним условием, а лежащий рядом ff_gen_drv.c от ST — лицензию с пятью условиями, и четвёртое требует исполнять код только на кристаллах ST.


205б.2 Что написано в разрешительных лицензиях

Главный вопрос для прошивки: что требует лицензия, когда код передаётся в двоичной форме — прошитым в прибор. Пересказ по текстам на диске:

Лицензия Что сказано о двоичной форме Где в тексте
Apache-2.0 (CMSIS, zcbor, Mbed TLS) распространять можно «in Source or Object form» при условиях: получатель получает копию лицензии, изменённые файлы помечены, уведомления сохранены, файл NOTICE, если он есть, передаётся п. 4 (a)–(d)
MIT (FreeRTOS) уведомление и текст разрешения включаются во все копии или существенные части единственный абзац условий
BSD-3-Clause (lwIP, littlefs, HAL вне пакета) в двоичной форме — воспроизвести уведомление, условия и отказ от гарантий в документации или других материалах условие 2
Zlib (nanopb) упоминание в документации продукта приветствуется, но не обязательно; изменённые исходники помечать условия 1 и 2
FatFs R0.11 (ChaN) условие одно — для исходного кода: сохранить уведомление условие 1

Файла NOTICE в каталогах CMSIS, zcbor и Mbed TLS на диске нет. Для разрешительных лицензий вывод из текстов один и тот же: код можно передавать внутри прибора, но в документации к прибору должны быть уведомления и тексты лицензий тех компонентов, которые этого требуют. Генератор собирает эти тексты в один файл LICENSES-THIRD-PARTY.txt (58 774 байта для девяти компонентов с файлом LICENSE) — его прикладывают к руководству.

Лицензии ST. SLA0044 (текст — в LICENSE.txt примеров, Rev6, октябрь 2025) разрешает передачу в двоичной форме без уведомления, если код встроен в кристалл ST (условие 2), требует исполнять код только на кристаллах ST или вместе с ними (условие 4) и запрещает такое использование, при котором код оказался бы под условиями открытых лицензий — GPL, EPL, Apache, BSD, MIT перечислены прямо (условие 5). SLA0048 пакета содержит те же по смыслу условия 2, 4 и 5.


205б.3 GPL и LGPL в прошивке

У копилефт-лицензий условие другое: вместе с двоичным кодом — исходники.

Отдельно — столкновение с лицензиями ST. Условие 5 SLA0044 запрещает использовать код ST так, чтобы он попал под открытые условия; GPL в нём названа прямо. Код под GPL и библиотека USB от ST в одной прошивке — это два текста с противоположными требованиями к одному и тому же образу.


205б.4 SBOM: два формата и два готовых примера на диске

SBOM — таблица составных частей программы: имя, версия, поставщик, лицензия, контрольная сумма. Форматов два, оба — JSON:

Готовые примеры уже есть на диске. ST кладёт в архив STM32CubeF1 файл sbom_cdx.json — CycloneDX 1.5, 46 компонентов, сделан сторонней программой анализа. Zephyr несёт свой генератор SPDX (west spdx, каталог zspdx): пишет SPDX 2.3 в текстовом виде, список лицензий SPDX версии 3.12 (499 идентификаторов), а лицензию файла ищет только по метке SPDX-License-Identifier: в первых 20 строках.

Этого мало для кода ST и старых библиотек: из 39 файлов опыта метка SPDX есть у 13. Остальным нужен разбор текста заголовка.


205б.5 Свой генератор: по дереву исходников на ПК

sbom205.py собирает дерево прибора из архивов на диске и описывает его. Лицензию файла он ищет в первых 80 строках — сначала метку SPDX, потом известные тексты:

def detect(text):
    """Лицензия по тексту заголовка или файла LICENSE. None — ничего не сказано; 'SEE-LICENSE' — отсылка к файлу."""
    m = re.search(r"SPDX-License-Identifier:\s*(.+)", text)
    if m:
        return m.group(1).strip().rstrip("*/").strip()
    t = re.sub(r"\s+", " ", re.sub(r"^[ \t]*[*/#;]+ ?", "", text, flags=re.M))
    if "Ultimate Liberty license SLA0044" in t or "terms of the SLA0044 license shall apply" in t:
        return "LicenseRef-ST-SLA0044"

Порядок важен. Пятипунктная лицензия ST начинается теми же словами, что BSD, — «Redistribution and use in source and binary forms», — поэтому сначала ищется признак «только кристаллы ST», и лишь потом считаются три условия BSD:

        if "must execute solely and exclusively on microcontroller" in t:
            return "LicenseRef-ST-5-Clause"                 # похоже на BSD, но условий пять, и четвёртое — только кристаллы ST

Итог по 39 файлам: метка SPDX — 13, узнанный текст — 13, отсылка к LICENSE компонента — 9, в заголовке ничего — 4 (три файла nanopb и pbuf.c из lwIP, у которого текст лицензии начинается с 81-й строки). Если файл молчит, берётся лицензия компонента из его LICENSE; если нет и её — файл получает NOASSERTION и выпуск останавливается.

Так и вышло в первом прогоне: в своём коде лежал app/ringbuf.c, взятый «откуда-то», без строки о лицензии. Генератор ответил нет лицензии: ./app/ringbuf.c, итог компонента — NOASSERTION. После добавления строки SPDX-License-Identifier: ошибок 0.

На выходе три файла: sbom.spdx.json, sbom.cdx.json и LICENSES-THIRD-PARTY.txt. Дата внутри постоянная, пространство имён SPDX и серийный номер CycloneDX выводятся из контрольных сумм файлов — два прогона дали отчёты, совпавшие байт в байт. SBOM воспроизводим так же, как прошивка в разделе 201а, и его можно хранить рядом с merged.hex в журнале выпусков.


205б.6 Сверка: все файлы найдены, лицензии совпали

Проверка раздела сверяет отчёт с деревом и с двумя чужими реализациями:

Что сверялось Итог
файлов в дереве / в SPDX 39 / 39, у каждого SHA-1 и SHA-256 пересчитаны
код проверки 12 пакетов совпал с функцией calculateVerificationCode из zspdx
идентификаторы лицензий 5 — в списке SPDX 3.12 из Zephyr; 4 — LicenseRef-… с пояснением в hasExtractedLicensingInfos
метка SPDX в первых 20 строках (сканер Zephyr) 13 файлов, у всех тот же ответ, что у своего генератора
лицензия в заголовке ↔ лицензия компонента расхождений 0
SBOM от ST (sbom_cdx.json) 7 общих компонентов: версии совпали у всех, лицензии — у 6

Расхождение одно — FatFs: у ST в SBOM BSD-3-Clause, а в заголовке ff.c той же версии R0.11 — одно условие, в ff_gen_drv.c — пять условий ST. Чей SBOM «прав» — вопрос не к генератору; генератор показал, что написано в файлах, и указал место расхождения.

Сканер Zephyr в окружении Windows сначала нашёл не 13, а 11 файлов: он открывает файл в кодировке системы (здесь cp1251), и два файла своего кода с русскими комментариями в UTF-8 не прочитались. С PYTHONUTF8=1 — 13.


205б.7 Грабли

«Лицензия как у папки». В одной папке FatFs — лицензия с одним условием и лицензия ST с пятью. SBOM строится по файлам, а итог компонента — выражение LicenseRef-FatFs-ChaN AND LicenseRef-ST-5-Clause.

«Похоже на BSD». Пятипунктная лицензия ST начинается словами BSD. Поиск по первой фразе запишет её как BSD-3-Clause и потеряет условие «только кристаллы ST». Признаки ограничений проверяются раньше общих.

Лицензия ниже двадцатой строки. У pbuf.c текст начинается с 81-й строки, после описания модуля. Сканер по первым строкам его не видит; выручает LICENSE компонента — если он есть.

Файл «откуда-то». Кусок кода без строки о лицензии — самая частая дыра. Генератор должен останавливать выпуск на NOASSERTION, а не молча приписывать лицензию проекта.

Два номера соглашения ST в одном пакете. License.md называет у библиотеки USB соглашение SLA0044, Package_license.md того же пакета — SLA0048, файлы библиотеки — SLA0044. В SBOM пишется то, что в файле, а расхождение отмечается.

Версия «из заголовка». У nanopb в pb.h записано nanopb-1.0.0-dev, а в library.json — 0.4.9. У CMSIS cmsis_version.h даёт 5.1 (версия ядра CMSIS-Core), а описание пакета — 5.4.0. В SBOM указывают, откуда взята версия, и берут её из одного и того же места у всех выпусков.

Кодировка у сканера. Чужой сканер, читающий файлы в кодировке системы, пропускает файлы с русскими комментариями в UTF-8 — без ошибки, просто «лицензия не найдена».

GPL «через зависимость». Mbed TLS позволяет выбрать GPL-2.0, но выбор делает получатель кода. Если в документах выпуска выбор не записан, SBOM с выражением OR остаётся вопросом, а не ответом.


205б.8 Итоги

Дальше: раздел 206 «Сертификация: подтверждение соответствия и радиомодули».

Открыть в интерактивном справочнике