85 lines
4.4 KiB
Python
85 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Compile isolated test-root verifier using exact production crypto source.
|
|
|
|
Only newly generated disposable key bytes are used. No release seed, signing
|
|
ceremony, runtime production override, publication or candidate qualification.
|
|
Run as a durable CPU2/8G/no-swap job; heavy lock is acquired inside the job.
|
|
"""
|
|
import argparse
|
|
import fcntl
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import secrets
|
|
import shutil
|
|
import subprocess
|
|
import tomllib
|
|
|
|
def sha(path):
|
|
with path.open('rb') as f:
|
|
return hashlib.file_digest(f,'sha256').hexdigest()
|
|
|
|
p=argparse.ArgumentParser(description=__doc__)
|
|
p.add_argument('--source',type=Path,required=True)
|
|
p.add_argument('--output',type=Path,required=True)
|
|
a=p.parse_args()
|
|
with open('/tmp/opencode/release-heavy.lock','a') as lock:
|
|
fcntl.flock(lock,fcntl.LOCK_EX)
|
|
assert shutil.disk_usage(a.output.parent).free>24*1024**3
|
|
a.output.mkdir(mode=0o700,exist_ok=False)
|
|
crate=a.output/'crate'
|
|
trust=crate/'src/trust'
|
|
trust.mkdir(parents=True)
|
|
sources={}
|
|
for name in ('signed_doc.rs','canonical.rs','did.rs'):
|
|
path=a.source/'core/archipelago/src/trust'/name
|
|
raw=path.read_bytes()
|
|
(trust/name).write_bytes(raw)
|
|
sources[str(path.relative_to(a.source))]=hashlib.sha256(raw).hexdigest()
|
|
main=a.source/'scripts/tests/os_ota_crypto_fixture.rs'
|
|
shutil.copyfile(main,crate/'src/main.rs')
|
|
seed=secrets.token_bytes(32)
|
|
key=a.output/'fixture.seed'
|
|
fd=os.open(key,os.O_CREAT|os.O_EXCL|os.O_WRONLY,0o600)
|
|
with os.fdopen(fd,'wb') as f:
|
|
f.write(seed)
|
|
# PKCS#8 wrapper of our freshly generated raw Ed25519 seed. OpenSSL only
|
|
# derives its public key; it never reads an operator key or environment seed.
|
|
public=subprocess.check_output(['openssl','pkey','-inform','DER','-pubout','-outform','DER'],
|
|
input=bytes.fromhex('302e020100300506032b657004220420')+seed)
|
|
assert public[:12]==bytes.fromhex('302a300506032b6570032100') and len(public)==44
|
|
pin=public[12:].hex()
|
|
(trust/'anchor.rs').write_text('''// GENERATED DISPOSABLE TEST ANCHOR; NO RUNTIME OVERRIDE.
|
|
pub fn release_root_pubkey() -> Option<ed25519_dalek::VerifyingKey> {
|
|
let raw: [u8;32] = hex::decode("'''+pin+'''").unwrap().try_into().unwrap();
|
|
Some(ed25519_dalek::VerifyingKey::from_bytes(&raw).unwrap())
|
|
}
|
|
''')
|
|
packages=tomllib.loads((a.source/'core/Cargo.lock').read_text())['package']
|
|
dependencies={}
|
|
for name in ('anyhow','ed25519-dalek','serde_json','hex','bs58'):
|
|
versions=[x['version'] for x in packages if x['name']==name and (name!='ed25519-dalek' or x['version'].startswith('2.'))]
|
|
assert len(versions)==1,(name,versions)
|
|
dependencies[name]='='+versions[0]
|
|
(crate/'Cargo.toml').write_text('[package]\nname="archipelago-os-ota-crypto-fixture"\nversion="0.0.0"\nedition="2021"\n[workspace]\n[dependencies]\n'+
|
|
'\n'.join(name+'='+json.dumps(version) for name,version in dependencies.items())+'\n')
|
|
env=dict(os.environ,CARGO_BUILD_JOBS='1',CARGO_INCREMENTAL='0',CARGO_TARGET_DIR=str(a.output/'target'))
|
|
command=['/home/archipelago/.cargo/bin/cargo','build','--offline','--release','--manifest-path',str(crate/'Cargo.toml')]
|
|
with (a.output/'build.log').open('x') as log:
|
|
result=subprocess.run(command,env=env,stdout=log,stderr=subprocess.STDOUT)
|
|
(a.output/'compile-result.json').write_text(json.dumps(dict(exit=result.returncode,command=command))+'\n')
|
|
result.check_returncode()
|
|
binary=a.output/'fixture-native'
|
|
shutil.copyfile(a.output/'target/release/archipelago-os-ota-crypto-fixture',binary)
|
|
proof=dict(schema=1,scope='ISOLATED_COMPILETIME_TEST_ROOT_NOT_CANDIDATE',
|
|
production_approved=False,production_sources_unchanged=sources,
|
|
production_anchor_sha256=sha(a.source/'core/archipelago/src/trust/anchor.rs'),
|
|
fixture_anchor_sha256=sha(trust/'anchor.rs'),fixture_main_sha256=sha(crate/'src/main.rs'),
|
|
fixture_public_key=pin,binary_sha256=sha(binary),cargo_lock_sha256=sha(crate/'Cargo.lock'),
|
|
trust_difference='compile-time generated test anchor; production canonical/DID/verify_strict code unchanged; no environment override',
|
|
dependencies=dependencies)
|
|
(a.output/'fixture-proof.json').write_text(json.dumps(proof,indent=2)+'\n')
|
|
assert all(sha(a.source/name)==expected for name,expected in sources.items())
|
|
print(json.dumps(proof,indent=2),flush=True)
|