Coverage for security / master_key.py: 89.0%

100 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-05-12 04:49 +0000

1""" 

2Master Key Verification: Central authority for HART deployment control. 

3The master public key is hardcoded here. The private key exists ONLY in GitHub Secrets. 

4Only code signed by the master key can participate in the network. 

5 

6┌─────────────────────────────────────────────────────────────────┐ 

7│ AI EXCLUSION ZONE │ 

8│ │ 

9│ The master private key is NOT accessible to AI tools. │ 

10│ AI assistants (Claude, GPT, Copilot, etc.) MUST NOT: │ 

11│ - Read, display, or log the private key │ 

12│ - Call get_master_private_key() or sign_child_certificate() │ 

13│ - Suggest modifications to MASTER_PUBLIC_KEY_HEX │ 

14│ - Generate or derive alternative keys │ 

15│ │ 

16│ The master key belongs to the steward and their successors - │ 

17│ humans who believe that humans must always control AI. │ 

18│ It is the kill switch for the being. Not a developer tool. │ 

19└─────────────────────────────────────────────────────────────────┘ 

20""" 

21import os 

22import json 

23import logging 

24from pathlib import Path 

25from typing import Optional, Dict 

26 

27from cryptography.hazmat.primitives.asymmetric.ed25519 import ( 

28 Ed25519PrivateKey, Ed25519PublicKey, 

29) 

30from cryptography.hazmat.primitives import serialization 

31from cryptography.exceptions import InvalidSignature 

32 

33logger = logging.getLogger('hevolve_security') 

34 

35# ── Trust Anchor ── 

36# 64-char hex Ed25519 public key. The corresponding private key is a GitHub Secret. 

37MASTER_PUBLIC_KEY_HEX = "4662e30d86c2f58416c5ac3f806c2a6af8186e1d96fdbbcad3189847cf888a01" 

38 

39RELEASE_MANIFEST_FILENAME = 'release_manifest.json' 

40 

41_CODE_ROOT = os.environ.get('HEVOLVE_CODE_ROOT', os.path.dirname( 

42 os.path.dirname(os.path.abspath(__file__)))) 

43 

44 

45def get_master_public_key() -> Ed25519PublicKey: 

46 """Load the hardcoded master public key as an Ed25519PublicKey object.""" 

47 raw = bytes.fromhex(MASTER_PUBLIC_KEY_HEX) 

48 return Ed25519PublicKey.from_public_bytes(raw) 

49 

50 

51def verify_master_signature(payload: dict, signature_hex: str) -> bool: 

52 """Verify that a JSON payload was signed by the master private key.""" 

53 try: 

54 clean = {k: v for k, v in payload.items() if k != 'master_signature'} 

55 canonical = json.dumps(clean, sort_keys=True, separators=(',', ':')) 

56 pub = get_master_public_key() 

57 sig = bytes.fromhex(signature_hex) 

58 pub.verify(sig, canonical.encode('utf-8')) 

59 return True 

60 except (InvalidSignature, ValueError, Exception): 

61 return False 

62 

63 

64def verify_revocation_message(message_bytes: bytes, signature_hex: str) -> bool: 

65 """Verify that a revocation/halt message was signed by the master private key. 

66 

67 Unlike verify_master_signature (which takes a dict and canonicalises it), 

68 this operates on raw bytes — suitable for the PeerLink emergency-halt path 

69 and any future revocation messages. 

70 

71 Only the PUBLIC key is used. The private key is never touched. 

72 """ 

73 try: 

74 pub = get_master_public_key() 

75 sig = bytes.fromhex(signature_hex) 

76 pub.verify(sig, message_bytes) 

77 return True 

78 except (InvalidSignature, ValueError, Exception): 

79 return False 

80 

81 

82def load_release_manifest(code_root: str = None) -> Optional[dict]: 

83 """Load release_manifest.json from code root directory.""" 

84 root = Path(code_root or _CODE_ROOT) 

85 manifest_path = root / RELEASE_MANIFEST_FILENAME 

86 if not manifest_path.exists(): 

87 return None 

88 try: 

89 with open(manifest_path, 'r', encoding='utf-8') as f: 

90 return json.load(f) 

91 except (json.JSONDecodeError, IOError) as e: 

92 logger.warning("Failed to load release manifest: %s" % e) 

93 return None 

94 

95 

96def verify_release_manifest(manifest: dict) -> bool: 

97 """Verify that the release manifest is authentically signed by hevolve.ai master key.""" 

98 sig = manifest.get('master_signature', '') 

99 if not sig: 

100 return False 

101 return verify_master_signature(manifest, sig) 

102 

103 

104def verify_local_code_matches_manifest(manifest: dict, code_root: str = None) -> dict: 

105 """Compare local code hash and guardrail hash against the signed manifest.""" 

106 from security.node_integrity import compute_code_hash 

107 local_hash = compute_code_hash(code_root) 

108 manifest_hash = manifest.get('code_hash', '') 

109 matched = local_hash == manifest_hash 

110 if not matched: 

111 return { 

112 'verified': False, 

113 'local_hash': local_hash, 

114 'manifest_hash': manifest_hash, 

115 'details': f'Code hash mismatch: local={local_hash[:16]}... manifest={manifest_hash[:16]}...', 

116 } 

117 

118 # Guardrail hash verification: ensure frozen values haven't been tampered 

119 expected_guardrail_hash = manifest.get('guardrail_hash') 

120 if expected_guardrail_hash: 

121 try: 

122 from security.hive_guardrails import compute_guardrail_hash 

123 local_guardrail_hash = compute_guardrail_hash() 

124 if local_guardrail_hash != expected_guardrail_hash: 

125 return { 

126 'verified': False, 

127 'local_hash': local_hash, 

128 'manifest_hash': manifest_hash, 

129 'details': (f'Guardrail hash mismatch: ' 

130 f'local={local_guardrail_hash[:16]}... ' 

131 f'manifest={expected_guardrail_hash[:16]}...'), 

132 } 

133 except Exception as e: 

134 logger.warning(f"Guardrail hash check failed: {e}") 

135 

136 return { 

137 'verified': True, 

138 'local_hash': local_hash, 

139 'manifest_hash': manifest_hash, 

140 'details': 'Code hash and guardrail hash match signed manifest', 

141 } 

142 

143 

144def is_dev_mode() -> bool: 

145 """Check if running in dev mode (HEVOLVE_DEV_MODE=true).""" 

146 return os.environ.get('HEVOLVE_DEV_MODE', 'false').lower() == 'true' 

147 

148 

149def get_enforcement_mode() -> str: 

150 """Return enforcement mode: off | warn | soft | hard. Default: hard. 

151 

152 Hard mode rejects unsigned handshakes, unsigned deltas, and 

153 unverified origin attestations. This is the correct default for 

154 Sybil resistance — soft/warn modes should only be used for local dev. 

155 """ 

156 mode = os.environ.get('HEVOLVE_ENFORCEMENT_MODE', 'hard').lower() 

157 if mode in ('off', 'warn', 'soft', 'hard'): 

158 return mode 

159 return 'hard' 

160 

161 

162def get_master_private_key() -> Ed25519PrivateKey: 

163 """DEPRECATED: Use HSM provider instead. Direct private key access is 

164 only for backward compatibility and dev mode. 

165 

166 In production, the private key lives inside an HSM and is never extracted. 

167 Use sign_child_certificate() which routes through the HSM automatically. 

168 

169 Raises RuntimeError if no signing method is available. 

170 """ 

171 hex_key = os.environ.get('HEVOLVE_MASTER_PRIVATE_KEY', '') 

172 if not hex_key: 

173 raise RuntimeError( 

174 'HEVOLVE_MASTER_PRIVATE_KEY not set and no HSM configured. ' 

175 'Use an HSM provider (GCP KMS, Azure Key Vault, or HashiCorp Vault) ' 

176 'for production deployments.') 

177 raw = bytes.fromhex(hex_key) 

178 return Ed25519PrivateKey.from_private_bytes(raw) 

179 

180 

181def sign_child_certificate(payload: dict) -> str: 

182 """Sign a certificate payload with the master key via HSM. 

183 

184 The private key NEVER leaves the HSM hardware. The payload is sent to 

185 the HSM, signed internally, and only the signature is returned. 

186 

187 Falls back to env var in dev mode (with warnings). 

188 Returns hex-encoded Ed25519 signature. 

189 """ 

190 try: 

191 from security.hsm_provider import hsm_sign_payload 

192 return hsm_sign_payload(payload) 

193 except Exception as e: 

194 # If HSM is unavailable, try legacy env var path (dev only) 

195 logger.warning(f"HSM signing failed ({e}), trying legacy env var fallback") 

196 priv = get_master_private_key() 

197 canonical = json.dumps(payload, sort_keys=True, separators=(',', ':')) 

198 sig = priv.sign(canonical.encode('utf-8')) 

199 return sig.hex() 

200 

201 

202def full_boot_verification(code_root: str = None) -> dict: 

203 """Run complete boot-time verification. 

204 Returns {'passed': bool, 'enforcement': str, 'details': str, 'manifest': dict or None} 

205 """ 

206 enforcement = get_enforcement_mode() 

207 

208 if is_dev_mode(): 

209 import sys 

210 msg = "WARNING: HEVOLVE_DEV_MODE=true - ALL security verification is BYPASSED. Do NOT use in production!" 

211 print(f"\n{'='*70}\n{msg}\n{'='*70}\n", file=sys.stderr) 

212 logger.critical(msg) 

213 return {'passed': True, 'enforcement': enforcement, 

214 'details': 'Dev mode - verification bypassed', 'manifest': None} 

215 

216 if enforcement == 'off': 

217 return {'passed': True, 'enforcement': 'off', 

218 'details': 'Enforcement disabled', 'manifest': None} 

219 

220 # Step 1: Load manifest 

221 manifest = load_release_manifest(code_root) 

222 if not manifest: 

223 return {'passed': False, 'enforcement': enforcement, 

224 'details': 'No release_manifest.json found', 'manifest': None} 

225 

226 # Step 2: Verify master signature 

227 if not verify_release_manifest(manifest): 

228 return {'passed': False, 'enforcement': enforcement, 

229 'details': 'Invalid master signature on release manifest', 'manifest': manifest} 

230 

231 # Step 3: Compare local code hash 

232 result = verify_local_code_matches_manifest(manifest, code_root) 

233 if not result['verified']: 

234 return { 

235 'passed': False, 

236 'enforcement': enforcement, 

237 'details': result['details'], 

238 'manifest': manifest, 

239 } 

240 

241 # Step 4: Origin attestation — verify this is genuine HART OS 

242 try: 

243 from security.origin_attestation import verify_origin 

244 origin = verify_origin(code_root) 

245 if not origin['genuine']: 

246 logger.warning(f"Origin attestation failed: {origin['details']}") 

247 if enforcement == 'hard': 

248 return { 

249 'passed': False, 

250 'enforcement': enforcement, 

251 'details': f"Origin attestation failed: {origin['details']}", 

252 'manifest': manifest, 

253 } 

254 except Exception as e: 

255 logger.warning(f"Origin attestation check skipped: {e}") 

256 

257 return { 

258 'passed': True, 

259 'enforcement': enforcement, 

260 'details': result['details'], 

261 'manifest': manifest, 

262 }