first commit
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
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
|
||||
"""
|
||||
Reference in New Issue
Block a user