11from pathlib import Path
22
3- from fastapi import APIRouter , HTTPException
3+ from fastapi import APIRouter , Depends , HTTPException
44from pydantic import BaseModel , Field
55
6+ from hybrid_pki .api .security import require_mutation_access
67from hybrid_pki .classical .ca import (
78 create_intermediate_ca_certificate ,
89 create_root_ca_certificate ,
@@ -117,7 +118,7 @@ def ensure_file_exists(path: Path, description: str) -> None:
117118 )
118119
119120
120- @router .post ("/ca/root/init" )
121+ @router .post ("/ca/root/init" , dependencies = [ Depends ( require_mutation_access )] )
121122def init_root_ca (request : RootCARequest ):
122123 """
123124 Generate a classical Root CA.
@@ -128,6 +129,12 @@ def init_root_ca(request: RootCARequest):
128129 - Root CA certificate PEM
129130 - Root CA certificate DER
130131 """
132+ if ROOT_KEY_PATH .exists () or ROOT_CERT_PATH .exists ():
133+ raise HTTPException (
134+ status_code = 409 ,
135+ detail = "Root CA already exists; remove it explicitly before reinitializing." ,
136+ )
137+
131138 ROOT_DIR .mkdir (parents = True , exist_ok = True )
132139
133140 private_key = generate_private_key (request .algorithm )
@@ -174,7 +181,7 @@ def init_root_ca(request: RootCARequest):
174181 }
175182
176183
177- @router .post ("/ca/intermediate/init" )
184+ @router .post ("/ca/intermediate/init" , dependencies = [ Depends ( require_mutation_access )] )
178185def init_intermediate_ca (request : IntermediateCARequest ):
179186 """
180187 Generate an Intermediate CA signed by the Root CA.
@@ -235,7 +242,7 @@ def init_intermediate_ca(request: IntermediateCARequest):
235242 }
236243
237244
238- @router .post ("/certificates/server/issue" )
245+ @router .post ("/certificates/server/issue" , dependencies = [ Depends ( require_mutation_access )] )
239246def issue_classical_server_certificate (request : ServerCertificateRequest ):
240247 """
241248 Issue a classical server certificate signed by the Intermediate CA.
@@ -323,7 +330,10 @@ def verify_classical_server_certificate(request: VerifyCertificateRequest):
323330 """
324331 Verify a classical server certificate against the Intermediate CA and Root CA.
325332 """
326- certificate_path = Path (request .certificate_path )
333+ certificate_path = Path (request .certificate_path ).resolve ()
334+ issued_root = ISSUED_DIR .resolve ()
335+ if issued_root not in certificate_path .parents :
336+ raise HTTPException (status_code = 400 , detail = "Certificate path must be inside certs/issued" )
327337
328338 ensure_file_exists (certificate_path , "Server certificate" )
329339 ensure_file_exists (INTERMEDIATE_CERT_PATH , "Intermediate CA certificate" )
@@ -367,7 +377,7 @@ def verify_classical_server_certificate(request: VerifyCertificateRequest):
367377 }
368378
369379
370- @router .post ("/certificates/server/revoke" )
380+ @router .post ("/certificates/server/revoke" , dependencies = [ Depends ( require_mutation_access )] )
371381def revoke_classical_server_certificate (request : RevokeCertificateRequest ):
372382 """
373383 Revoke a classical server certificate.
0 commit comments