Skip to content

Commit ee6df10

Browse files
authored
[pyjks] Fill in jks.bks and other modules, improved constructors (#10815)
1 parent a12b205 commit ee6df10

File tree

5 files changed

+149
-76
lines changed

5 files changed

+149
-76
lines changed

stubs/pyjks/jks/bks.pyi

Lines changed: 94 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,124 @@
1-
from _typeshed import Incomplete
2-
from typing_extensions import Final, Self
1+
from _typeshed import SupportsKeysAndGetItem, Unused
2+
from typing_extensions import Final, Literal, Self, TypeAlias
33

44
from .jks import TrustedCertEntry
55
from .util import AbstractKeystore, AbstractKeystoreEntry
66

7+
_BksType: TypeAlias = Literal["bks", "uber"]
8+
_CertType: TypeAlias = Literal["X.509"]
9+
_EntryFormat: TypeAlias = Literal["PKCS8", "PKCS#8", "X.509", "X509", "RAW"]
10+
_BksVersion: TypeAlias = Literal[1, 2]
11+
712
ENTRY_TYPE_CERTIFICATE: Final = 1
813
ENTRY_TYPE_KEY: Final = 2
914
ENTRY_TYPE_SECRET: Final = 3
1015
ENTRY_TYPE_SEALED: Final = 4
16+
1117
KEY_TYPE_PRIVATE: Final = 0
1218
KEY_TYPE_PUBLIC: Final = 1
1319
KEY_TYPE_SECRET: Final = 2
20+
_KeyType: TypeAlias = Literal[0, 1, 2]
1421

1522
class AbstractBksEntry(AbstractKeystoreEntry):
16-
cert_chain: Incomplete
17-
def __init__(self, **kwargs) -> None: ...
23+
store_type: _BksType | None
24+
cert_chain: list[tuple[_CertType, bytes]]
25+
def __init__(
26+
self,
27+
*,
28+
cert_chain: list[tuple[_CertType, bytes]] = ...,
29+
encrypted: bytes | None = None,
30+
store_type: _BksType | None = None,
31+
alias: str,
32+
timestamp: int,
33+
**kwargs: Unused,
34+
) -> None: ...
1835

19-
class BksTrustedCertEntry(TrustedCertEntry): ...
36+
class BksTrustedCertEntry(TrustedCertEntry):
37+
store_type: _BksType | None # type: ignore[assignment]
2038

2139
class BksKeyEntry(AbstractBksEntry):
22-
type: Incomplete
23-
format: Incomplete
24-
algorithm: Incomplete
25-
encoded: Incomplete
26-
pkey_pkcs8: Incomplete
27-
pkey: Incomplete
28-
algorithm_oid: Incomplete
29-
public_key_info: Incomplete
30-
public_key: Incomplete
31-
key: Incomplete
32-
key_size: Incomplete
33-
def __init__(self, type, format, algorithm, encoded, **kwargs) -> None: ...
34-
def is_decrypted(self): ...
35-
def decrypt(self, key_password) -> None: ...
40+
type: _KeyType
41+
format: _EntryFormat
42+
algorithm: str
43+
encoded: bytes
44+
# type == KEY_TYPE_PRIVATE
45+
pkey_pkcs8: bytes
46+
pkey: bytes
47+
algorithm_oid: tuple[int, ...]
48+
# type == KEY_TYPE_PUBLIC
49+
public_key_info: bytes
50+
public_key: bytes
51+
# type == KEY_TYPE_SECRET
52+
key: bytes
53+
key_size: int
54+
def __init__(
55+
self,
56+
type: _KeyType,
57+
format: _EntryFormat,
58+
algorithm: str,
59+
encoded: bytes,
60+
*,
61+
cert_chain: list[tuple[_CertType, bytes]] = ...,
62+
encrypted: bytes | None = None,
63+
store_type: _BksType | None = None,
64+
alias: str,
65+
timestamp: int,
66+
**kwargs: Unused,
67+
) -> None: ...
3668
@classmethod
37-
def type2str(cls, t): ...
69+
def type2str(cls, t: _KeyType) -> Literal["PRIVATE", "PUBLIC", "SECRET"]: ...
70+
def is_decrypted(self) -> Literal[True]: ...
3871

3972
class BksSecretKeyEntry(AbstractBksEntry):
40-
key: Incomplete
41-
def __init__(self, **kwargs) -> None: ...
42-
def is_decrypted(self): ...
43-
def decrypt(self, key_password) -> None: ...
73+
key: bytes
74+
def is_decrypted(self) -> Literal[True]: ...
4475

4576
class BksSealedKeyEntry(AbstractBksEntry):
46-
def __init__(self, **kwargs) -> None: ...
47-
def __getattr__(self, name): ...
48-
def is_decrypted(self): ...
49-
def decrypt(self, key_password) -> None: ...
77+
# Properties provided by __getattr__
78+
nested: BksKeyEntry | None
79+
# __getattr__ proxies all attributes of nested BksKeyEntry after decrypting
80+
type: _KeyType
81+
format: _EntryFormat
82+
algorithm: str
83+
encoded: bytes
84+
# if type == KEY_TYPE_PRIVATE
85+
pkey_pkcs8: bytes
86+
pkey: bytes
87+
algorithm_oid: tuple[int, ...]
88+
# if type == KEY_TYPE_PUBLIC
89+
public_key_info: bytes
90+
public_key: bytes
91+
# if type == KEY_TYPE_SECRET
92+
key: bytes
93+
key_size: int
5094

5195
class BksKeyStore(AbstractKeystore):
52-
version: Incomplete
53-
def __init__(self, store_type, entries, version: int = 2) -> None: ...
96+
store_type: Literal["bks"]
97+
entries: dict[str, BksTrustedCertEntry | BksKeyEntry | BksSealedKeyEntry | BksSecretKeyEntry] # type: ignore[assignment]
98+
version: _BksVersion
99+
def __init__(
100+
self,
101+
store_type: Literal["bks"],
102+
entries: SupportsKeysAndGetItem[str, BksTrustedCertEntry | BksKeyEntry | BksSealedKeyEntry | BksSecretKeyEntry],
103+
version: _BksVersion = 2,
104+
) -> None: ...
54105
@property
55-
def certs(self): ...
106+
def certs(self) -> dict[str, BksTrustedCertEntry]: ...
56107
@property
57-
def secret_keys(self): ...
108+
def plain_keys(self) -> dict[str, BksKeyEntry]: ...
58109
@property
59-
def sealed_keys(self): ...
110+
def sealed_keys(self) -> dict[str, BksSealedKeyEntry]: ...
60111
@property
61-
def plain_keys(self): ...
112+
def secret_keys(self) -> dict[str, BksSecretKeyEntry]: ...
62113
@classmethod
63-
def loads(cls, data, store_password, try_decrypt_keys: bool = True) -> Self: ...
114+
def loads(cls, data: bytes, store_password: str, try_decrypt_keys: bool = True) -> Self: ...
64115

65116
class UberKeyStore(BksKeyStore):
66-
@classmethod
67-
def loads(cls, data, store_password, try_decrypt_keys: bool = True) -> Self: ...
68-
version: Incomplete
69-
def __init__(self, store_type, entries, version: int = 1) -> None: ...
117+
store_type: Literal["uber"] # type: ignore[assignment]
118+
version: Literal[1]
119+
def __init__(
120+
self,
121+
store_type: Literal["uber"],
122+
entries: SupportsKeysAndGetItem[str, BksTrustedCertEntry | BksKeyEntry | BksSealedKeyEntry | BksSecretKeyEntry],
123+
version: Literal[1] = 1,
124+
) -> None: ...

stubs/pyjks/jks/jks.pyi

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from _typeshed import Incomplete, SupportsKeysAndGetItem
1+
from _typeshed import SupportsKeysAndGetItem, Unused
22
from collections.abc import Iterable
3-
from typing import Any, NoReturn
3+
from typing import NoReturn, overload
44
from typing_extensions import Final, Literal, Self, TypeAlias
55

66
from .util import AbstractKeystore, AbstractKeystoreEntry
@@ -19,15 +19,16 @@ class TrustedCertEntry(AbstractKeystoreEntry):
1919
store_type: _JksType | None
2020
type: _CertType | None
2121
cert: bytes
22+
# NB! For most use cases, use TrustedCertEntry.new() classmethod.
2223
def __init__(
2324
self,
2425
*,
25-
type: _CertType = ...,
26-
cert: bytes = ...,
27-
store_type: _JksType = ...,
28-
alias: str = ...,
29-
timestamp: int = ...,
30-
**kwargs: Any,
26+
type: _CertType | None = None,
27+
cert: bytes,
28+
store_type: _JksType | None = None,
29+
alias: str,
30+
timestamp: int,
31+
**kwargs: Unused,
3132
) -> None: ...
3233
@classmethod
3334
def new(cls, alias: str, cert: bytes) -> Self: ... # type: ignore[override]
@@ -43,18 +44,31 @@ class PrivateKeyEntry(AbstractKeystoreEntry):
4344
def pkey_pkcs8(self) -> bytes: ...
4445
@property
4546
def algorithm_oid(self) -> tuple[int, ...]: ...
47+
# NB! For most use cases, use PrivateKeyEntry.new() classmethod.
48+
# Overloaded: must provide `encrypted` OR `pkey`, `pkey_pkcs8`, `algorithm_oid`
49+
@overload
4650
def __init__(
4751
self,
4852
*,
49-
cert_chain: list[tuple[_CertType, bytes]] = ...,
50-
encrypted: bool = ...,
51-
pkey: bytes = ...,
52-
pkey_pkcs8: bytes = ...,
53-
algorithm_oid: tuple[int, ...] = ...,
54-
store_type: _JksType = ...,
55-
alias: str = ...,
56-
timestamp: int = ...,
57-
**kwargs: Any,
53+
cert_chain: list[tuple[_CertType, bytes]],
54+
encrypted: bytes,
55+
store_type: _JksType | None = None,
56+
alias: str,
57+
timestamp: int,
58+
**kwargs: Unused,
59+
) -> None: ...
60+
@overload
61+
def __init__(
62+
self,
63+
*,
64+
cert_chain: list[tuple[_CertType, bytes]],
65+
pkey: bytes,
66+
pkey_pkcs8: bytes,
67+
algorithm_oid: tuple[int, ...],
68+
store_type: _JksType | None = None,
69+
alias: str,
70+
timestamp: int,
71+
**kwargs: Unused,
5872
) -> None: ...
5973
@classmethod
6074
def new( # type: ignore[override]
@@ -70,17 +84,22 @@ class SecretKeyEntry(AbstractKeystoreEntry):
7084
def key(self) -> bytes: ...
7185
@property
7286
def key_size(self) -> int: ...
87+
# Overloaded: must provide `sealed_obj` OR `algorithm`, `key`, `key_size`
88+
@overload
89+
def __init__(
90+
self, *, sealed_obj: bytes, store_type: _JksType | None = None, alias: str, timestamp: int, **kwargs: Unused
91+
) -> None: ...
92+
@overload
7393
def __init__(
7494
self,
7595
*,
76-
sealed_obj: Incomplete = ...,
77-
algorithm: str = ...,
78-
key: bytes = ...,
79-
key_size: int = ...,
80-
store_type: _JksType = ...,
81-
alias: str = ...,
82-
timestamp: int = ...,
83-
**kwargs: Any,
96+
algorithm: str,
97+
key: bytes,
98+
key_size: int,
99+
store_type: _JksType | None = None,
100+
alias: str,
101+
timestamp: int,
102+
**kwargs: Unused,
84103
) -> None: ...
85104
# Not implemented by pyjks
86105
@classmethod
@@ -98,6 +117,7 @@ class KeyStore(AbstractKeystore):
98117
@classmethod
99118
def loads(cls, data: bytes, store_password: str | None, try_decrypt_keys: bool = True) -> Self: ...
100119
def saves(self, store_password: str) -> bytes: ...
120+
# NB! For most use cases, use KeyStore.new() classmethod.
101121
def __init__(
102122
self, store_type: _JksType, entries: SupportsKeysAndGetItem[str, TrustedCertEntry | PrivateKeyEntry | SecretKeyEntry]
103123
) -> None: ...

stubs/pyjks/jks/rfc2898.pyi

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from _typeshed import Incomplete
1+
from pyasn1.type.namedtype import NamedTypes
2+
from pyasn1.type.univ import Sequence
23

3-
from pyasn1.type import univ
4-
5-
class PBEParameter(univ.Sequence):
6-
componentType: Incomplete
4+
class PBEParameter(Sequence):
5+
componentType: NamedTypes

stubs/pyjks/jks/rfc7292.pyi

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from _typeshed import Incomplete
21
from hashlib import _Hash
32
from typing_extensions import Final, Literal, TypeAlias
43

5-
from pyasn1.type import univ
4+
from pyasn1.type.namedtype import NamedTypes
5+
from pyasn1.type.univ import Sequence
66

77
PBE_WITH_SHA1_AND_TRIPLE_DES_CBC_OID: Final[tuple[int, ...]]
88
PURPOSE_KEY_MATERIAL: Final = 1
@@ -11,8 +11,8 @@ PURPOSE_MAC_MATERIAL: Final = 3
1111

1212
_Purpose: TypeAlias = Literal[1, 2, 3]
1313

14-
class Pkcs12PBEParams(univ.Sequence):
15-
componentType: Incomplete
14+
class Pkcs12PBEParams(Sequence):
15+
componentType: NamedTypes
1616

1717
def derive_key(
1818
hashfn: _Hash, purpose_byte: _Purpose, password_str: str, salt: bytes, iteration_count: int, desired_key_size: int

stubs/pyjks/jks/util.pyi

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
from _typeshed import FileDescriptorOrPath, SupportsKeysAndGetItem
1+
from _typeshed import FileDescriptorOrPath, SupportsKeysAndGetItem, Unused
22
from collections.abc import Iterable
33
from struct import Struct
4-
from typing import Any
54
from typing_extensions import Final, Literal, Self, TypeAlias
65

76
from .bks import BksKeyEntry
@@ -48,7 +47,7 @@ class AbstractKeystoreEntry:
4847
store_type: _KeystoreType | None
4948
alias: str
5049
timestamp: int
51-
def __init__(self, *, store_type: _KeystoreType = ..., alias: str = ..., timestamp: int = ..., **kwargs: Any) -> None: ...
50+
def __init__(self, *, store_type: _KeystoreType | None = None, alias: str, timestamp: int, **kwargs: Unused) -> None: ...
5251
@classmethod
5352
def new(cls, alias: str) -> Self: ...
5453
def is_decrypted(self) -> bool: ...

0 commit comments

Comments
 (0)