Skip to content

Commit 5c5853a

Browse files
committed
Fix COSE_Sign1 compliance: Use tag 18 instead of CWT tag 61
Signed-off-by: Alex Tzonkov <4975715+attzonko@users.noreply.github.com>
1 parent be123cc commit 5c5853a

2 files changed

Lines changed: 53 additions & 75 deletions

File tree

shortform_report-main/OcpReportLib.py

Lines changed: 39 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -629,71 +629,44 @@ def get_signed_corim_report(self) -> bytes:
629629
"""Returns the signed CoRIM report (COSE-Sign1)."""
630630
return self.signed_corim_report
631631

632-
def _sign_corim_report_internal(self, signer) -> bool:
633-
"""Sign the CoRIM report using COSE-Sign1 with the cwt library.
632+
def _sign_corim_report_internal(self, cose_key) -> bool:
633+
"""Sign the CoRIM report as COSE_Sign1 (CBOR tag 18) using cwt.COSE.
634634
635-
Uses the cwt (CBOR Web Token) library for better COSE compatibility.
636-
do not call directly, use either sign_corim_report_pem() or sign_corim_report_azure()
637-
which provide appropriate signer modules.
638-
"""
639-
# Get CoRIM payload as claims (cwt expects claims, not raw payload)
640-
corim_cbor = self.get_report_as_corim_cbor()
635+
Uses cwt.COSE.encode() to produce a proper COSE_Sign1 envelope,
636+
as required by the CoRIM spec:
637+
signed-corim = #6.18(COSE_Sign1_Tagged<corim-map>)
641638
642-
# For COSE signing, we need to create claims structure
643-
# The CoRIM data becomes the payload claim
644-
claims = {
645-
# Use a custom claim number for CoRIM data
646-
-65537: corim_cbor # Custom claim for CoRIM payload
647-
}
639+
The raw CoRIM CBOR is used directly as the COSE_Sign1 payload
640+
(no CWT claims wrapping).
648641
649-
# Sign using cwt library with the signer
650-
signed_corim_report = cwt.encode_and_sign(
651-
claims=claims,
652-
signers=[signer],
653-
tagged=True, # Use CBOR tag for COSE_Sign1
654-
)
642+
cose_key: A cwt.COSEKeyInterface (e.g. from cwt.COSEKey.from_pem()).
655643
656-
self.signed_corim_report = signed_corim_report
644+
Do not call directly; use sign_corim_report_pem() or
645+
sign_corim_report_azure().
646+
"""
647+
corim_cbor = self.get_report_as_corim_cbor()
648+
cose = cwt.COSE(alg_auto_inclusion=True, kid_auto_inclusion=True)
649+
self.signed_corim_report = cose.encode(corim_cbor, cose_key)
657650
return True
658651

659652
def sign_corim_report_pem(self, priv_key: bytes, algo: str, kid: str) -> bool:
660-
"""Sign the CoRIM report using COSE-Sign1 with the cwt library.
653+
"""Sign the CoRIM report as COSE_Sign1 (tag 18) using a PEM private key.
661654
662-
Uses the cwt (CBOR Web Token) library for better COSE compatibility.
655+
Uses cwt.COSE to produce a proper COSE_Sign1 envelope.
656+
657+
priv_key: PEM-encoded private key bytes.
658+
algo: Algorithm name (ES384, ES512, PS384, PS512).
659+
kid: Key identifier string for the unprotected header.
663660
"""
664661
try:
665-
# Load private key using cryptography
666-
pem = serialization.load_pem_private_key(
667-
priv_key, None, backend=default_backend()
668-
)
669-
670-
# Map algorithm to COSE algorithm identifier
671-
cose_alg = None
672-
if (
673-
algo == "ES512"
674-
and isinstance(pem, EllipticCurvePrivateKey)
675-
and pem.curve.name == "secp521r1"
676-
):
677-
cose_alg = -36 # ES512
678-
elif (
679-
algo == "ES384"
680-
and isinstance(pem, EllipticCurvePrivateKey)
681-
and pem.curve.name == "secp384r1"
682-
):
683-
cose_alg = -35 # ES384
684-
elif algo == "PS512" and isinstance(pem, RSAPrivateKey):
685-
cose_alg = -38 # PS512
686-
elif algo == "PS384" and isinstance(pem, RSAPrivateKey):
687-
cose_alg = -37 # PS384
688-
else:
689-
print(f"Unsupported algorithm/key combination: {algo} with {type(pem)}")
662+
algo_map = {"ES384": -35, "ES512": -36, "PS384": -37, "PS512": -38}
663+
cose_alg = algo_map.get(algo)
664+
if cose_alg is None:
665+
print(f"Unsupported algorithm: {algo}")
690666
return False
691667

692-
# Create Signer using cwt library
693-
signer = cwt.Signer.from_pem(priv_key, alg=cose_alg, kid=kid)
694-
695-
# sign and return result
696-
return self._sign_corim_report_internal(signer)
668+
cose_key = cwt.COSEKey.from_pem(priv_key, alg=cose_alg, kid=kid)
669+
return self._sign_corim_report_internal(cose_key)
697670

698671
except Exception as e:
699672
print(f"Error signing CoRIM with cwt: {e}")
@@ -767,20 +740,24 @@ def verify_signed_json_report(
767740
return decoded
768741

769742
def verify_signed_corim_report(
770-
self, signed_corim_report: bytes, pub_key: bytes, kid: str
743+
self, signed_corim_report: bytes, pub_key: bytes, kid: str,
744+
algo: int = -36,
771745
) -> bool:
772-
"""Verify the signed report using the provided public key.
746+
"""Verify a signed CoRIM report (COSE_Sign1, tag 18).
773747
774-
signed_corim_report: A bytes object containing the signed report as a CoRIM CBOR object.
775-
pub_key: A bytes object containing the public key used to verify the signed report, which corresponds to the SRP's 'kid'.
748+
signed_corim_report: Signed COSE_Sign1 bytes.
749+
pub_key: PEM-encoded public key bytes.
750+
kid: Key identifier string.
751+
algo: COSE algorithm identifier
752+
(default: -36 / ES512 for backward compatibility;
753+
use -35 for ES384).
776754
777-
Returns a dictionary containing the decoded short-form report payload.
755+
Returns True on success, raises Exception on failure.
778756
"""
779757
try:
780-
cwt.decode(
781-
data=signed_corim_report,
782-
keys=cwt.COSEKey.from_pem(pub_key, alg=-36, kid=kid),
783-
) # alg -36 is ES512
758+
cose_key = cwt.COSEKey.from_pem(pub_key, alg=algo, kid=kid)
759+
cose = cwt.COSE()
760+
cose.decode(signed_corim_report, cose_key)
784761
return True
785762

786763
except Exception as e:

shortform_report-main/cbor_human_inspector.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ def explain_cbor_tag(tag_num):
210210
"""Provide human-readable explanations for CBOR tags."""
211211
tag_explanations = {
212212
1: "POSIX timestamp (seconds since epoch)",
213-
18: "COSE-Sign (Multi-Signer COSE Signature)",
214-
61: "COSE-Sign1 (Single Signer COSE Signature)",
213+
18: "COSE_Sign1 (Single Signer COSE Signature)",
214+
61: "CWT (CBOR Web Token)",
215+
98: "COSE_Sign (Multi-Signer COSE Signature)",
215216
111: "Object Identifier (OID)",
216217
501: "CoRIM (CBOR Object Representation of Information Model)",
217218
506: "COMID (Concise Module Identifier)",
@@ -539,31 +540,31 @@ def inspect_corim_structure(cbor_data, show_raw_data=False):
539540
print("✅ This is a valid CoRIM structure")
540541
inspect_corim_content_details(decoded.value)
541542

542-
elif decoded.tag == 61: # COSE-Sign1 tag
543-
print("✅ This is a signed CoRIM with COSE-Sign1 signature")
543+
elif decoded.tag == 18: # COSE_Sign1 tag
544+
print("✅ This is a signed CoRIM with COSE_Sign1 signature")
544545
print("🔓 Extracting CoRIM payload from COSE signature...")
545546

546-
# Extract CoRIM from COSE-Sign1 structure
547+
# Extract CoRIM from COSE_Sign1 structure
547548
corim_payload = extract_corim_from_cose_sign1(decoded.value)
548549
if corim_payload:
549550
print("✅ Successfully extracted CoRIM payload from signature")
550551
inspect_corim_content_details(corim_payload)
551552
else:
552-
print("❌ Failed to extract CoRIM payload from COSE-Sign1 structure")
553+
print("❌ Failed to extract CoRIM payload from COSE_Sign1 structure")
553554

554-
elif decoded.tag == 18: # COSE-Sign tag
555-
print("✅ This is a signed CoRIM with COSE-Sign signature (multi-signer)")
555+
elif decoded.tag == 98: # COSE_Sign tag
556+
print("✅ This is a signed CoRIM with COSE_Sign signature (multi-signer)")
556557
print("🔓 Extracting CoRIM payload from COSE signature...")
557558

558-
# Extract CoRIM from COSE-Sign structure
559+
# Extract CoRIM from COSE_Sign structure
559560
corim_payload = extract_corim_from_cose_sign(decoded.value)
560561
if corim_payload:
561562
print("✅ Successfully extracted CoRIM payload from signature")
562563
inspect_corim_content_details(corim_payload)
563564
else:
564-
print("❌ Failed to extract CoRIM payload from COSE-Sign structure")
565+
print("❌ Failed to extract CoRIM payload from COSE_Sign structure")
565566
else:
566-
print(f"❌ Expected CoRIM tag (501), COSE-Sign1 tag (61), or COSE-Sign tag (18), found tag {decoded.tag}")
567+
print(f"❌ Expected CoRIM tag (501), COSE_Sign1 tag (18), or COSE_Sign tag (98), found tag {decoded.tag}")
567568
else:
568569
print(f"❌ Expected CBOR tag at top level, found: {type(decoded)}")
569570

@@ -892,8 +893,8 @@ def show_help():
892893
print(" python cbor_human_inspector.py signed_corim.jws")
893894
print("\nSUPPORTED FORMATS:")
894895
print(" • Unsigned CoRIMs (CBOR tag 501)")
895-
print(" • COSE-Sign1 signed CoRIMs (CBOR tag 61)")
896-
print(" • COSE-Sign multi-signer CoRIMs (CBOR tag 18)")
896+
print(" • COSE_Sign1 signed CoRIMs (CBOR tag 18)")
897+
print(" • COSE_Sign multi-signer CoRIMs (CBOR tag 98)")
897898
print("\nOUTPUT:")
898899
print(" The tool provides detailed analysis including:")
899900
print(" • CoRIM structure validation")

0 commit comments

Comments
 (0)