forked from osbuild/osbuild
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This stage allows you to create new (random) ed25519 keys as used by `ostree sign`. The primary usecase for this is composefs. You can generate a transient key-pair during the build (unique to the build) that binds the initrd to the userspace tree. You put the public key in the initrd, sign the resulting commit with the private key and then throw away the private key. During boot of a (secureboot trusted) initrd, we use this public key to validate that we're booting the right commit. This is similar to how the transient kernel module signatures work. It similarly generates a keypair during the kernel rpm build, sign the modules, throw away the private key and embed the public key in the kernel binary. Of course, this stage can also be used to generate keys used for persistant signatures.
- Loading branch information
1 parent
d52738d
commit 4234118
Showing
1 changed file
with
96 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#!/usr/bin/python3 | ||
"""Generate ed25519 public/private keypair in format used by `ostree sign`. | ||
This is used with the org.osbuild.ostree.sign stage, and these can be | ||
used with composefs to tie an initrd and ostree commit together. See | ||
https://ostreedev.github.io/ostree/composefs/#signatures for details | ||
of how this works. | ||
Notes: | ||
- Requires 'openssl' in the buildroot. | ||
""" | ||
|
||
import base64 | ||
import os | ||
import subprocess | ||
import sys | ||
import tempfile | ||
|
||
import osbuild.api | ||
|
||
SCHEMA_2 = r""" | ||
"options": { | ||
"additionalProperties": false, | ||
"required": ["publickey", "secretkey"], | ||
"properties": { | ||
"publickey": { | ||
"description": "Path of generated public key", | ||
"type": "string", | ||
"pattern": "^\\/(?!\\.\\.)((?!\\/\\.\\.\\/).)+$" | ||
}, | ||
"secretkey": { | ||
"description": "Path of generated secret key", | ||
"type": "string", | ||
"pattern": "^\\/(?!\\.\\.)((?!\\/\\.\\.\\/).)+$" | ||
} | ||
} | ||
} | ||
""" | ||
|
||
|
||
def openssl(*args): | ||
args = list(args) | ||
print("openssl " + " ".join(args), file=sys.stderr) | ||
subprocess.run(["openssl"] + args, | ||
encoding="utf8", | ||
stdout=sys.stderr, | ||
input=None, | ||
check=True) | ||
|
||
|
||
def openssl_stdout(*args): | ||
args = list(args) | ||
print("openssl " + " ".join(args), file=sys.stderr) | ||
res = subprocess.run(["openssl"] + args, | ||
stdout=subprocess.PIPE, | ||
input=None, | ||
check=True) | ||
|
||
return res.stdout | ||
|
||
# Based on gen_ed25519_keys() in https://github.com/ostreedev/ostree/blob/main/tests/libtest.sh | ||
|
||
|
||
def main(args, options): | ||
tree = args["tree"] | ||
pubkeyfile = os.path.join(tree, options["publickey"].lstrip("/")) | ||
seckeyfile = os.path.join(tree, options["secretkey"].lstrip("/")) | ||
|
||
with tempfile.TemporaryDirectory(dir=tree) as tmpdir: | ||
# Generate key | ||
pemfile = os.path.join(tmpdir, "key.pem") | ||
openssl("genpkey", "-algorithm", "ed25519", "-outform", "PEM", "-out", pemfile) | ||
|
||
# Extract the seed/public parts from generated key (last 32 byte in PEM file) | ||
pubkey = openssl_stdout("pkey", "-outform", "DER", "-pubout", "-in", pemfile)[-32:] | ||
seed = openssl_stdout("pkey", "-outform", "DER", "-in", pemfile)[-32:] | ||
|
||
# Private key is seed and public key joined | ||
seckey = seed + pubkey | ||
|
||
# Ostree stores keys in base64 | ||
pubkey_b64 = base64.b64encode(pubkey).decode("utf8") | ||
seckey_b64 = base64.b64encode(seckey).decode("utf8") | ||
|
||
with open(pubkeyfile, "w", encoding="utf8") as f: | ||
f.write(pubkey_b64) | ||
|
||
with open(seckeyfile, "w", encoding="utf8") as f: | ||
f.write(seckey_b64) | ||
|
||
|
||
if __name__ == '__main__': | ||
stage_args = osbuild.api.arguments() | ||
r = main(stage_args, | ||
stage_args["options"]) | ||
sys.exit(r) |