// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2019 Luxoft Sweden AB // Copyright (C) 2018 Pelagicore AG // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \page installer.html \ingroup qtappman \title Package Installation \brief Discusses the package installation infrastructure. \keyword Installer \section1 Dynamically Installing, Updating, and Removing Packages After applications have been packaged by the \l {Packager}{\c appman-packager} tool, they can be installed by the application manager at runtime. There are two interfaces for this functionality: \list \li A QML interface for use within the application manager process. \li A D-Bus interface for use by any process that is allowed to talk to the application manager's \c PackageManager interface. \endlist Both interfaces are very similar and are described in the PackageManager. \note A prerequisite for dynamically installed application packages is a valid \l {Configuration}{\c installationDir configuration} for the application manager. \section1 Packages The application manager has its own \l {Package Format}. It comes with the \l {Packager}{\c appman-packager} command-line tool, for you to create and verify those packages. \section1 Installation Sources When triggering a package installation, you have to provide a URL to the application manager as the source of the package. Out of the box, the application manager accepts the following schemes: \table \header \li Scheme \li Description \row \li \c file:// \li A local filesystem path. \row \li \c http://, \c https:// and \c ftp:// \li A remote path that is downloaded via QNetworkAccessManager. \row \li \c socket:// \li A path to a UNIX-domain socket in the local filesystem. This is very useful for streaming in packages, if you do not want to (or can) use the built-in downloader, or if your packages are wrapped inside another customer-specific distribution file format. \endtable All of the above methods work asynchronously and also support streaming: this means that the actual installation is done while the package is being downloaded. If the package is successfully verified after the download, it only needs a quick finalization step. Otherwise, if an error occurred, the installation process is simply canceled and rolled back. \section1 Public Key Infrastructure To use signed packages, you require a Public Key Infrastructure (PKI) to support this, which means that you need two Certificate Authorities (CAs): \list \li A \e {Developer CA}: responsible for creating certificates that are distributed to developers in P12 format. The developers use these certificates to developer-sign their packages, using the \l {Packager}, before submitting to an app store. \li An \e {App-Store CA}: responsible for creating certificates for use by app store server back ends to store-sign packages, before they are downloaded and installed onto devices. \endlist Both these CAs can be the same or they can be derived from a common root CA. For the device, you need to install one or both of these CA certificates, including any root or intermediary ones. But, this depends on the type of package you want the user to be able to install. Which CA certificates to load is specified via \l {ca certificates} {the config file}. The application manager sources have a script, \c tests/data/certificates/create-test-certificates.sh, that sets up such a PKI for the internal unit tests. This script is \b not for use in production, but only for use in developing with signed packages. New in 6.11: \list \li Developer certificates can be bound to one or more specific package IDs, to prevent shadowing or replacement of packages that are not owned by the developer. See \l {Binding Developer Certificates to Package IDs}{below} for more information. \li Developer certificates need to have the \c decipherOnly bit set in the \e{Key Usage} X509 extension, while App-Store certificates need to have the \c encipherOnly bit set. This ensures that developer and app-store certificates cannot be used interchangeably. The X509 format is not easily extensible, but these otherwise unused key-usage bits can easily be set in any tool used for creating certificates. \li The fingerprints of issuer certificates can optionally be white-listed in the configuration file. \li Certificate Revocation Lists (CRLs) can be loaded to revoke developer or app-store certificates. \endlist \section2 Creating Developer Certificates The examples below use the \c{openssl} command-line tool to create keys, CSRs, and certificates. You are however free to use any other tool that is able to create X.509v3 and PKCS#12 certificates. For a developer to receive a developer certificate, they would typically generate a private key and a certificate signing request (CSR) for their package: \badcode $ openssl req -new -nodes -newkey rsa:2048 -subj "/CN=Developer 1" \ -addext "subjectAltName=URI:qtam://packageid/my-package-id" \ -keyout developer.key -out developer-req.csr \endcode Please note that the actual parameters like key size and subject name would depend on your PKI policy. In this example, a 2048-bit RSA key is created with the common name \e "Developer 1". The \c{subjectAltName} extension is used to bind the developer certificate to one or more specific package IDs, in this case \c my-package-id. See \l{Binding Developer Certificates to Package IDs}{below for more information}. The \c developer-req.csr file would then be sent to the Developer CA for signing, while the \c developer.key file is kept private by the developer. On the CA side, the CSR is then verified and signed to create the developer certificate. Please note that developer certificates need to have the \c decipherOnly bit set in the \e{Key Usage} X509 extension. \badcode $ openssl ca -batch -config dev-ca.conf -policy signing_policy -extensions signing_req \ -out developer.crt -infiles developer-req.csr \endcode This generates the signed \c developer.crt file, which is then sent back to the developer. The final step for developers is to bundle their private key and the signed certificate into a P12 file, which is the format that the \l {Packager}{\c appman-packager} tool expects: \badcode $ openssl pkcs12 -export -out developer.p12 -in developer.crt -inkey developer.key \endcode \section2 Binding Developer Certificates to Package IDs Up to version 6.11, all developer certificates were treated equally, meaning that a developer could sign any package. From version 6.11 onwards, developer certificates can be bound to one or more specific package IDs, to prevent shadowing or replacement of packages that are not owned by the developer. This ID list is stored in the \c{subjectAltName} X.509v3 extension of the developer certificate as \c {URI:qtam://packageid/...} entries. This extension is conventionally used to store alternative domain names for HTTPS server certificates. As with HTTPS certificates, you can use the \c{*} wildcard character to match multiple package IDs. For example, a developer certificate with the following \c{subjectAltName} extension: \badcode subjectAltName = URI:qtam://packageid/com.vendor.*, URI:qtam://packageid/io.qt.example \endcode would allow the developer to create and sign packages with an ID starting with \c{com.vendor.}, as well as the specific package with the ID \c{io.qt.example}. \note Adding this information is \b optional for developer certificates to retain backwards compatibility. However you are highly encouraged to add this information to your developer certificates to improve security. If you still need to issue an unrestricted developer certificate, you can use \c{URI:qtam://packageid/*} to explicitly allow all package IDs. \section2 Developer Signing Packages Each package can only have exactly one developer signature. A developer would sign their package as follows, after obtaining a valid developer certificate in P12 format (see above). \badcode $ appman-packager dev-sign-package the-pkg.ampkg the-pkg.dev-signed.ampkg developer.p12 \endcode This takes the input package \c the-pkg.ampkg, signs it with the \c developer.p12 signature, and writes the output to \c the-pkg.dev-signed.ampkg. The signed package would then be uploaded/sent to an app-store for further processing. \section2 Store Signing Packages Each package can only have exactly one app-store signature. When a developer submits a package to an app-store, the app-store server backend and/or a human tester would verify the \e developer signature on the package first: \badcode $ appman-packager dev-verify-package --verbose the-pkg.dev-signed.ampkg dev-ca.crt intermediate-ca.crt root-ca.crt \endcode The actual number and names of the requires CA certificates depends on your PKI setup. The above is just an example. Next, the contents of the package should be verified: first and foremost the contents of \c info.yaml, but also the actual application code. Finally the package is signed with a \e store key: \badcode $ appman-packager store-sign-package the-pkg.signed.ampkg the.pkg.dev-store-signed.ampkg store.p12 \endcode This takes the input package \c the-pkg.dev-signed.ampkg, signs it with the \c store.p12 signature, and writes the output to \c the-pkg.dev-store-signed.ampkg. The store-signed package would then be made available for download and installation. In order to differentiate between developer and store certificates (even if you use the same CA for everything), store certificates need to have the \c encipherOnly bit set in the \e{Key Usage} X509 extension. \section1 Related Content \list \li \l {Package Format} \li \l {Packager} \li \l {PackageManager}{PackageManager API} \endlist */