Skip to content

Commit

Permalink
doc: Various improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
theofidry committed Oct 30, 2023
1 parent 5163fbb commit fc0bac3
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 92 deletions.
2 changes: 1 addition & 1 deletion doc/code-isolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ conflicts.
To illustrate that issue with an example: we are building a console application `myapp.phar` which relies on the library
Symfony YAML 2.8.0 which execute a given PHP script.

```bash
```shell
# Usage of the application we are building
myapp.phar myscript.php
```
Expand Down
14 changes: 11 additions & 3 deletions doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -770,12 +770,17 @@ available:
- `SHA1`
- `SHA256`
- `SHA512`
- `OPENSSL`
- `OPENSSL` (deprecated)

By default PHARs are `SHA1` signed.
By default, PHARs are `SHA1` signed.

The `OPENSSL` algorithm will require to provide [a key][key].

!!! warning

The OpenSSL signature has been deprecated as of Box 4.4.0. If you are wondering why check out
[the signing best practices].


### The private key (`key`)

Expand Down Expand Up @@ -825,7 +830,9 @@ With the configuration excerpt:

Then the `Phar::getMetadata()` will return `['application_version' => '1.0.0-dev']` array.

**CAUTION**: Your callable function must be readable by your autoloader.
!!! warning

Your callable function must be readable by your autoloader.

That means, for Composer, in previous example, we require to have such kind of declaration in your `composer.json` file.

Expand Down Expand Up @@ -1044,6 +1051,7 @@ The short commit hash will only be used if no tag is available.
[requirement-checker]: requirement-checker.md#requirements-checker
[security]: #security
[shebang]: #shebang-shebang
[the signing best practices]: ./phar-signing.md#phar-signing-best-practices
[stub-stub]: #stub-stub
[stub]: #stub
[symfony-finder]: https://symfony.com/doc/current//components/finder.html
Expand Down
8 changes: 4 additions & 4 deletions doc/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ if (false === in_array(PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
The shebang `#!/usr/bin/env php` is required to the auto-detection of the type of the script. This allows to use it as
follows:

```bash
$ chmod +x bin/acme.php
$ ./bin/acme.php
$ php bin/acme.php # still works
```shell
chmod +x bin/acme.php
./bin/acme.php
php bin/acme.php # still works
# Without the shebang line, you can only use the latter
```

Expand Down
2 changes: 1 addition & 1 deletion doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ box help
The project provides a `Makefile` in which the most common commands have been registered such as fixing the coding
style or running the test.

```bash
```shell
make
```

Expand Down
36 changes: 18 additions & 18 deletions doc/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,54 +17,54 @@ The preferred method of installation is to use the Box PHAR which can be downloa

You can install Box with [Phive][phive]

```bash
$ phive install humbug/box
```shell
phive install humbug/box
```

To upgrade `box` use the following command:

```bash
$ phive update humbug/box
```shell
phive update humbug/box
```


## Composer

You can install Box with [Composer][composer]:

```bash
$ composer global require humbug/box
```shell
composer global require humbug/box
```

If you cannot install it because of a dependency conflict or you prefer to install it for your project, we recommend
you to take a look at [bamarni/composer-bin-plugin][bamarni/composer-bin-plugin]. Example:

```bash
$ composer require --dev bamarni/composer-bin-plugin
$ composer bin box require --dev humbug/box
```shell
composer require --dev bamarni/composer-bin-plugin
composer bin box require --dev humbug/box

$ vendor/bin/box
vendor/bin/box
```

## Homebrew

To install box using [Homebrew](https://brew.sh), you need to tap the box formula first

```bash
$ brew tap box-project/box
$ brew install box
```shell
brew tap box-project/box
brew install box
```

The `box` command is now available to run from anywhere in the system:

```bash
$ box -v
```shell
box -v
```

To upgrade `box` use the following command:

```bash
$ brew upgrade box
```shell
brew upgrade box
```

## GitHub
Expand All @@ -73,7 +73,7 @@ You may download the Box PHAR directly from the [GitHub release][releases] direc
You should however beware that it is not as secure as downloading it from the other mediums.
Hence, it is recommended to check the signature when doing so:

```
```shell
# Do adjust the URL based on the latest release
wget -O box.phar "https://github.com/box-project/box/releases/download/4.4.0/box.phar"
wget -O box.phar.asc "https://github.com/box-project/box/releases/download/4.4.0/box.phar.asc"
Expand Down
98 changes: 54 additions & 44 deletions doc/phar-signing.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# PHAR signing best practices

1. [Built-in PHAR API](#built-in-phar-api)
1. [How to sign your PHAR](#how-to-sign-your-phar)
1. [How it works](#how-it-works)
1. [Why it is bad](#why-it-is-bad)
1. [How to sign your PHAR](#how-to-sign-your-phar)
1. [How it works](#how-it-works)
1. [Why it is bad](#why-it-is-bad)
1. [How to (properly) sign your PHAR](#how-to-properly-sign-your-phar)
1. [Create a new GPG-key](#create-a-new-gpg-key)
1. [Manually signing](#manually-signing)
1. [Generate the encryption key](#generate-the-encryption-key)
1. [Secure your encryption key](#secure-your-encryption-key)
1. [Sign your PHAR](#sign-your-phar)
1. [Verifying the PHAR signature](#verifying-the-phar-signature)
1. [Create a new GPG-key](#create-a-new-gpg-key)
1. [Manually signing](#manually-signing)
1. [Generate the encryption key](#generate-the-encryption-key)
1. [Secure your encryption key](#secure-your-encryption-key)
1. [Sign your PHAR](#sign-your-phar)
1. [Verifying the PHAR signature](#verifying-the-phar-signature)
1. [Automatically sign in GitHub Actions](#automatically-sign-in-github-actions)

There is two idiomatic ways to secure a PHAR:
Expand All @@ -35,8 +35,8 @@ $phar->setSignatureAlgorithm($algo, $privateKey);
There is various algorithm available. The most "secure" one would be `Phar::OPENSSL` with an
OpenSSL private key. For instance:

```
$ openssl genrsa -des3 -out acme-phar-private.pem 4096
```shell
openssl genrsa -des3 -out acme-phar-private.pem 4096
```

```php
Expand Down Expand Up @@ -94,7 +94,7 @@ there is ways to void the signature:
file (the public key), but in the context the attacker could inject code to the PHAR this is unlikely to be a real
prevention measure.

So to conclude, **this security mechanism CANNOT prevent modifications of the archive itself.** It is NOT a reliable
So to conclude, **this security mechanism CANNOT prevent modifications of the archive itself.** It is **NOT** a reliable
protection measure.

The good news, there is a solution.
Expand All @@ -106,14 +106,15 @@ The good news, there is a solution.

The first step is to create a new GPG-key. You can either do that via a GUI or via the CLI like this:

```
$ gpg --gen-key
```shell
gpg --gen-key
```

It will ask for some questions. It is recommended to use a passphrase (ideally generated and managed by a reputable
password manager). In the end, you will end up with something like this:

```
# $ gpg --gen-key output
pub ed25519 2023-10-21 [SC] [expires: 2026-10-20]
96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
uid Théo Fidry <[email protected]>
Expand All @@ -123,8 +124,8 @@ sub cv25519 2023-10-21 [E] [expires: 2026-10-20]
In this case the interesting part is `96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08` which is the key ID. You can also check
the list of your GPG keys like so:

```
$ gpg --list-secret-keys --keyid-format=long
```shell
gpg --list-secret-keys --keyid-format=long

#
# Other keys displayed too
Expand All @@ -135,22 +136,24 @@ uid [ultimate] Théo Fidry <theo.fidry+phar-signing-example@exam
ssb cv25519/765C0E3CCBC7D7D3 2023-10-21 [E] [expires: 2026-10-20]
```

The interesting part is the `96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08` which is the key-ID.
Like above, you see the key ID `96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08`.

To make the key accessible for others we should now send it to a keyserver.
To make the key accessible for others we should now send it to a keyserver[^1].

```
$ gpg --keyserver keys.openpgp.org --send-key 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
```shell
gpg --keyserver keys.openpgp.org --send-key 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
```

†: There is several OpenPGP Keyservers. It is recommended to push your keys to [keys.openpgp.org] _at least_, but you
can also push it to other servers if you wish to.
[^1]:

There is several OpenPGP Keyservers. It is recommended to push your keys to [keys.openpgp.org] _at least_, but you
can also push it to other servers if you wish to.

You can also already generate a revocation certificate for the key. Should the key be compromised you can then send the
revocation certificate to the keyserver to invalidate the signing key.

```
$ gpg --output revoke-96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08.asc --gen-revoke 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
```shell
gpg --output revoke-96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08.asc --gen-revoke 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
```

This will leave you with a revocation certificate in the file `revoke-96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08.asc`
Expand All @@ -167,13 +170,15 @@ private GPG key.

In order to use the key to encrypt files, you need to first export it:

```
$ gpg --export --armor 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08 > keys.asc
$ gpg --export-secret-key --armor 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08 >> keys.asc
```shell
gpg --export --armor 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08 > keys.asc
gpg --export-secret-key --armor 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08 >> keys.asc
```

That will leave the public and private key in a single file. Anyone that has that file can sign on your behalf! So keep
that file secure at all times and make sure it never accidentally shows up in your git repository!
!!! warning

That will leave the public and private key in a single file. Anyone that has that file can sign on your behalf! So keep
that file secure at all times and make sure it never accidentally shows up in your git repository.


### Secure your encryption key
Expand All @@ -196,9 +201,9 @@ it is better to not keep that decrypted key around.

You first need to encrypt `keys.asc.gpg` into `keys.asc`:

```
```shell
# If you are locally:
$ gpg keys.asc.gpg
gpg keys.asc.gpg
# In another environment: CI or other. You should use an environment variable
# or a temporary file to avoid printing the password in clear text.
echo $DECRYPT_KEY_PASSPHRASE | gpg --passphrase-fd 0 keys.asc.gpg
Expand All @@ -208,14 +213,14 @@ cat $(.decrypt-key-passphrase) | gpg --passphrase-fd 0 keys.asc.gpg

Import the decrypted key if it is not already present on the machine:

```
$ gpg --batch --yes --import keys.asc
```shell
gpg --batch --yes --import keys.asc
```

Sign your file:

```
$ gpg \
```shell
gpg \
--batch \
--passphrase="$GPG_KEY_96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08_PASSPHRASE" \
--local-user 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08 \
Expand All @@ -241,12 +246,12 @@ documentation:
gpg --keyserver hkps://keys.openpgp.org --recv-keys 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
```

However not everyone expose what is their GPG key ID. So sometimes to avoid bad surprises, you
However not everyone exposes what is their GPG key ID. So sometimes to avoid bad surprises, you
can look up for similar issuers to the key ID given by the `.asc`:

```
```shell
# Verify the signature
$ gpg --verify bin/command.phar.asc bin/command.phar
gpg --verify bin/command.phar.asc bin/command.phar

# Example of output:
gpg: Signature made Sat 21 Oct 16:58:05 2023 CEST
Expand All @@ -256,19 +261,21 @@ gpg: Good signature from "Théo Fidry <[email protected]

If the key ID was not provided before, you can try to look it up to check it was properly registered to a keyserver:

```
$ gpg --keyserver https://keys.openpgp.org --search-keys "[email protected]"
```shell
gpg --keyserver https://keys.openpgp.org --search-keys "[email protected]"
```

Also note that when dealing with PHARs, the above steps are automatically done for you by [PHIVE][phive].
!!! info

Also note that when dealing with PHARs, the above steps are automatically done for you by [PHIVE][phive].


## Automatically sign in GitHub Actions

The first step is to add [environment secrets to your repository][github-environment-secrets]:

```
$ gpg --export-secret-key --armor 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
```shell
gpg --export-secret-key --armor 96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08
# Paste the content into a secret environment variable
GPG_KEY_96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08

Expand All @@ -277,15 +284,17 @@ GPG_KEY_96C8013A3CC293C465EE3FBB03B2F4DF7A20DF08_PASSPHRASE
```

Then you need to:

- Build your PHAR
- Import the GPG key
- Sign your PHAR
- Publish your PHAR

I highly recommend to build your PHAR as part of your regular workflows. Then the other steps can be enable on release
only. The following is an example of GitHub workflow:
only. The following is an example of [GitHub workflow][github-workflow]:

```yaml
# .github/workflows/release.yaml
name: Release

on:
Expand Down Expand Up @@ -380,5 +389,6 @@ Credits:
[box-release-workflow]: https://github.com/box-project/box/blob/main/.github/workflows/release.yaml
[keys.openpgp.org]: https://keys.openpgp.org/about
[github-environment-secrets]: https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions
[github-workflow]: https://docs.github.com/en/actions/using-workflows
[phive]: https://phar.io/
[jar]: https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jarGuide.html
Loading

0 comments on commit fc0bac3

Please sign in to comment.