Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/securesystemslib/signer/_signer.py: 77%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

26 statements  

1"""Signer interface""" 

2 

3from __future__ import annotations 

4 

5import logging 

6from abc import ABCMeta, abstractmethod 

7from typing import Callable 

8 

9from securesystemslib.signer._key import Key 

10from securesystemslib.signer._signature import Signature 

11 

12logger = logging.getLogger(__name__) 

13 

14# NOTE Signer dispatch table is defined here so it's usable by Signer, 

15# but is populated in __init__.py (and can be appended by users). 

16SIGNER_FOR_URI_SCHEME: dict[str, type] = {} 

17"""Signer dispatch table for ``Signer.from_priv_key()`` 

18 

19See ``securesystemslib.signer.SIGNER_FOR_URI_SCHEME`` for default URI schemes, 

20and how to register custom implementations. 

21""" 

22 

23# SecretsHandler is a function the calling code can provide to Signer: 

24# SecretsHandler will be called if Signer needs additional secrets. 

25# The argument is the name of the secret ("PIN", "passphrase", etc). 

26# Return value is the secret string. 

27SecretsHandler = Callable[[str], str] 

28 

29 

30class Signer(metaclass=ABCMeta): 

31 """Signer interface that supports multiple signing implementations. 

32 

33 Usage example:: 

34 

35 signer = Signer.from_priv_key_uri(uri, pub_key) 

36 sig = signer.sign(b"data") 

37 

38 Note that signer implementations may raise errors (during both 

39 ``Signer.from_priv_key_uri()`` and ``Signer.sign()``) that are not 

40 documented here: examples could include network errors or file read errors. 

41 Applications should use generic try-except here if unexpected raises are 

42 not an option. 

43 

44 See ``SIGNER_FOR_URI_SCHEME`` for supported private key URI schemes. 

45 

46 Interactive applications may also define a secrets handler that allows 

47 asking for user secrets if they are needed:: 

48 

49 from getpass import getpass 

50 

51 def sec_handler(secret_name:str) -> str: 

52 return getpass(f"Enter {secret_name}: ") 

53 

54 signer = Signer.from_priv_key_uri(uri, pub_key, sec_handler) 

55 

56 Applications can provide their own Signer and Key implementations:: 

57 

58 from securesystemslib.signer import Signer, SIGNER_FOR_URI_SCHEME 

59 from mylib import MySigner 

60 

61 SIGNER_FOR_URI_SCHEME[MySigner.MY_SCHEME] = MySigner 

62 

63 This way the application code using signer API continues to work with 

64 default signers but now also uses the custom signer when the proper URI is 

65 used. 

66 """ 

67 

68 @abstractmethod 

69 def sign(self, payload: bytes) -> Signature: 

70 """Signs a given payload by the key assigned to the Signer instance. 

71 

72 Arguments: 

73 payload: The bytes to be signed. 

74 

75 Returns: 

76 Returns a "Signature" class instance. 

77 """ 

78 raise NotImplementedError # pragma: no cover 

79 

80 @classmethod 

81 @abstractmethod 

82 def from_priv_key_uri( 

83 cls, 

84 priv_key_uri: str, 

85 public_key: Key, 

86 secrets_handler: SecretsHandler | None = None, 

87 ) -> Signer: 

88 """Factory constructor for a given private key URI 

89 

90 Returns a specific Signer instance based on the private key URI and the 

91 supported uri schemes listed in ``SIGNER_FOR_URI_SCHEME``. 

92 

93 Args: 

94 priv_key_uri: URI that identifies the private key 

95 public_key: Key that is the public portion of this private key 

96 secrets_handler: Optional function that may be called if the 

97 signer needs additional secrets (like a PIN or passphrase). 

98 secrets_handler should return the requested secret string. 

99 

100 Raises: 

101 ValueError: Incorrect arguments 

102 Other Signer-specific errors: These could include OSErrors for 

103 reading files or network errors for connecting to a KMS. 

104 """ 

105 

106 scheme, _, _ = priv_key_uri.partition(":") 

107 if scheme not in SIGNER_FOR_URI_SCHEME: 

108 raise ValueError(f"Unsupported private key scheme {scheme}") 

109 

110 signer = SIGNER_FOR_URI_SCHEME[scheme] 

111 return signer.from_priv_key_uri(priv_key_uri, public_key, secrets_handler) # type: ignore 

112 

113 @property 

114 @abstractmethod 

115 def public_key(self) -> Key: 

116 """ 

117 Returns: 

118 Public key the signer is based off. 

119 """ 

120 raise NotImplementedError