142 lines
4.1 KiB
Python
142 lines
4.1 KiB
Python
from typing import Any, ClassVar, Literal
|
|
from abc import ABCMeta, abstractmethod
|
|
from .types import SegmentsDict, JSONSignatureDict
|
|
from ..errors import InvalidKeyTypeError
|
|
from ..registry import Header
|
|
|
|
__all__ = [
|
|
"HeaderMember",
|
|
"CompactSignature",
|
|
"FlattenedJSONSignature",
|
|
"GeneralJSONSignature",
|
|
"JWSAlgModel",
|
|
]
|
|
|
|
|
|
class HeaderMember:
|
|
"""A header member of the JSON signature. It is combined with protected header,
|
|
and unprotected header.
|
|
"""
|
|
|
|
def __init__(self, protected: Header | None = None, header: Header | None = None):
|
|
#: protected header
|
|
self.protected = protected
|
|
#: unprotected header
|
|
self.header = header
|
|
|
|
def headers(self) -> Header:
|
|
rv: Header = {}
|
|
if self.header:
|
|
rv.update(self.header)
|
|
|
|
# protected header is preferred
|
|
if self.protected:
|
|
rv.update(self.protected)
|
|
return rv
|
|
|
|
def set_kid(self, kid: str) -> None:
|
|
if self.header is None:
|
|
self.header = {}
|
|
self.header["kid"] = kid
|
|
|
|
|
|
class CompactSignature:
|
|
"""JSON Web Signature object for compact mode. This object is used to
|
|
represent the JWS instance.
|
|
"""
|
|
|
|
def __init__(self, protected: Header, payload: bytes):
|
|
#: protected header
|
|
self.protected = protected
|
|
#: payload content in bytes
|
|
self.payload = payload
|
|
self.segments: SegmentsDict = {}
|
|
|
|
def headers(self) -> Header:
|
|
"""Returns protected header values in dict."""
|
|
return self.protected
|
|
|
|
def set_kid(self, kid: str) -> None:
|
|
self.protected["kid"] = kid
|
|
|
|
|
|
class FlattenedJSONSignature:
|
|
"""JSON Signature object that represents a flattened JSON serialization."""
|
|
|
|
#: mark it as flattened
|
|
flattened: ClassVar[bool] = True
|
|
|
|
def __init__(self, member: HeaderMember, payload: bytes):
|
|
#: the only header member
|
|
self.member: HeaderMember = member
|
|
#: payload content in bytes
|
|
self.payload: bytes = payload
|
|
self.signature: JSONSignatureDict | None = None
|
|
self.segments: SegmentsDict = {}
|
|
|
|
@property
|
|
def members(self) -> list[HeaderMember]:
|
|
"""A list of header members. For flattened JSON serialization, there will
|
|
be only one header member."""
|
|
return [self.member]
|
|
|
|
def headers(self) -> Header:
|
|
"""Header values in dict."""
|
|
return self.member.headers()
|
|
|
|
|
|
class GeneralJSONSignature:
|
|
"""JSON Signature object that represents a general JSON serialization."""
|
|
|
|
#: mark it as not flattened (general)
|
|
flattened: ClassVar[bool] = False
|
|
|
|
def __init__(self, members: list[HeaderMember], payload: bytes):
|
|
#: a list of header members
|
|
self.members: list[HeaderMember] = members
|
|
#: payload content in bytes
|
|
self.payload: bytes = payload
|
|
self.signatures: list[JSONSignatureDict] = []
|
|
self.segments: SegmentsDict = {}
|
|
|
|
|
|
class JWSAlgModel(metaclass=ABCMeta):
|
|
"""Interface for JWS algorithm. JWA specification (RFC7518) SHOULD
|
|
implement the algorithms for JWS with this base implementation.
|
|
"""
|
|
|
|
name: str
|
|
description: str
|
|
recommended: bool = False
|
|
security_warning: str | None = None
|
|
|
|
key_type = "oct"
|
|
algorithm_type: Literal["JWS"] = "JWS"
|
|
algorithm_location = "sig"
|
|
algorithm_security = 0
|
|
|
|
def check_key(self, key: Any) -> None:
|
|
key.check_use("sig")
|
|
if key.key_type != self.key_type:
|
|
raise InvalidKeyTypeError(f"Algorithm '{self.name}' requires '{self.key_type}' key")
|
|
key.check_alg(self.name)
|
|
|
|
@abstractmethod
|
|
def sign(self, msg: bytes, key: Any) -> bytes:
|
|
"""Sign the text msg with a private/sign key.
|
|
|
|
:param msg: message bytes to be signed
|
|
:param key: private key to sign the message
|
|
:return: bytes
|
|
"""
|
|
|
|
@abstractmethod
|
|
def verify(self, msg: bytes, sig: bytes, key: Any) -> bool:
|
|
"""Verify the signature of text msg with a public/verify key.
|
|
|
|
:param msg: message bytes to be signed
|
|
:param sig: result signature to be compared
|
|
:param key: public key to verify the signature
|
|
:return: boolean
|
|
"""
|