python-pkcs11 0.10.1__cp315-cp315-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pkcs11/__init__.py +50 -0
- pkcs11/_pkcs11.cp315-win_amd64.pyd +0 -0
- pkcs11/_pkcs11.pxd +964 -0
- pkcs11/_pkcs11.pyi +35 -0
- pkcs11/_pkcs11.pyx +2327 -0
- pkcs11/attributes.py +272 -0
- pkcs11/constants.py +559 -0
- pkcs11/defaults.py +121 -0
- pkcs11/exceptions.py +410 -0
- pkcs11/mechanisms.py +862 -0
- pkcs11/py.typed +0 -0
- pkcs11/types.py +1457 -0
- pkcs11/util/__init__.py +17 -0
- pkcs11/util/dh.py +79 -0
- pkcs11/util/dsa.py +108 -0
- pkcs11/util/ec.py +143 -0
- pkcs11/util/rsa.py +95 -0
- pkcs11/util/x509.py +136 -0
- python_pkcs11-0.10.1.dist-info/METADATA +399 -0
- python_pkcs11-0.10.1.dist-info/RECORD +23 -0
- python_pkcs11-0.10.1.dist-info/WHEEL +5 -0
- python_pkcs11-0.10.1.dist-info/licenses/LICENSE +21 -0
- python_pkcs11-0.10.1.dist-info/top_level.txt +1 -0
pkcs11/util/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import SupportsInt
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def biginteger(value: SupportsInt) -> bytes:
|
|
7
|
+
"""
|
|
8
|
+
Returns a PKCS#11 biginteger bytestream from a Python integer or
|
|
9
|
+
similar type (e.g. :class:`asn1crypto.core.Integer`).
|
|
10
|
+
|
|
11
|
+
:param int value: Value
|
|
12
|
+
:rtype: bytes
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
value_int = int(value) # In case it's a asn1 type or similar
|
|
16
|
+
|
|
17
|
+
return value_int.to_bytes((value_int.bit_length() + 7) // 8, byteorder="big")
|
pkcs11/util/dh.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Key handling utilities for Diffie-Hellman keys.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
from asn1crypto.algos import DHParameters
|
|
10
|
+
from asn1crypto.core import Integer
|
|
11
|
+
|
|
12
|
+
from pkcs11.constants import Attribute
|
|
13
|
+
from pkcs11.util import biginteger
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from pkcs11.types import DomainParameters, PublicKey
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def decode_dh_domain_parameters(der: bytes) -> dict[Attribute, Any]:
|
|
20
|
+
"""
|
|
21
|
+
Decode DER-encoded Diffie-Hellman domain parameters.
|
|
22
|
+
|
|
23
|
+
:param bytes der: DER-encoded parameters
|
|
24
|
+
:rtype: dict(Attribute,*)
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
params = DHParameters.load(der)
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
Attribute.BASE: biginteger(params["g"]),
|
|
31
|
+
Attribute.PRIME: biginteger(params["p"]),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def encode_dh_domain_parameters(obj: DomainParameters) -> bytes:
|
|
36
|
+
"""
|
|
37
|
+
Encode DH domain parameters into DER-encoded format.
|
|
38
|
+
|
|
39
|
+
Calculates the subprime if it isn't available.
|
|
40
|
+
|
|
41
|
+
:param DomainParameters obj: domain parameters
|
|
42
|
+
:rtype: bytes
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
asn1 = DHParameters(
|
|
46
|
+
{
|
|
47
|
+
"g": int.from_bytes(obj[Attribute.BASE], byteorder="big"),
|
|
48
|
+
"p": int.from_bytes(obj[Attribute.PRIME], byteorder="big"),
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return asn1.dump()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def encode_dh_public_key(key: PublicKey) -> bytes:
|
|
56
|
+
"""
|
|
57
|
+
Encode DH public key into RFC 3279 DER-encoded format.
|
|
58
|
+
|
|
59
|
+
:param PublicKey key: public key
|
|
60
|
+
:rtype: bytes
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
asn1 = Integer(int.from_bytes(key[Attribute.VALUE], byteorder="big"))
|
|
64
|
+
|
|
65
|
+
return asn1.dump()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def decode_dh_public_key(der: bytes) -> bytes:
|
|
69
|
+
"""
|
|
70
|
+
Decode a DH public key from RFC 3279 DER-encoded format.
|
|
71
|
+
|
|
72
|
+
Returns a `biginteger` encoded as bytes.
|
|
73
|
+
|
|
74
|
+
:param bytes der: DER-encoded public key
|
|
75
|
+
:rtype: bytes
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
asn1 = Integer.load(der)
|
|
79
|
+
return biginteger(asn1)
|
pkcs11/util/dsa.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Key handling utilities for DSA keys, domain parameters and signatures..
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
from asn1crypto.algos import DSASignature
|
|
10
|
+
from asn1crypto.core import Integer
|
|
11
|
+
from asn1crypto.keys import DSAParams
|
|
12
|
+
|
|
13
|
+
from pkcs11.constants import Attribute
|
|
14
|
+
from pkcs11.util import biginteger
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from pkcs11.types import DomainParameters, PublicKey
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def decode_dsa_domain_parameters(der: bytes) -> dict[Attribute, Any]:
|
|
21
|
+
"""
|
|
22
|
+
Decode RFC 3279 DER-encoded Dss-Params.
|
|
23
|
+
|
|
24
|
+
:param bytes der: DER-encoded parameters
|
|
25
|
+
:rtype: dict(Attribute,*)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
params = DSAParams.load(der)
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
Attribute.BASE: biginteger(params["g"]),
|
|
32
|
+
Attribute.PRIME: biginteger(params["p"]),
|
|
33
|
+
Attribute.SUBPRIME: biginteger(params["q"]),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def encode_dsa_domain_parameters(obj: DomainParameters) -> bytes:
|
|
38
|
+
"""
|
|
39
|
+
Encode RFC 3279 DER-encoded Dss-Params.
|
|
40
|
+
|
|
41
|
+
:param DomainParameters obj: domain parameters
|
|
42
|
+
:rtype: bytes
|
|
43
|
+
"""
|
|
44
|
+
asn1 = DSAParams(
|
|
45
|
+
{
|
|
46
|
+
"g": int.from_bytes(obj[Attribute.BASE], byteorder="big"),
|
|
47
|
+
"p": int.from_bytes(obj[Attribute.PRIME], byteorder="big"),
|
|
48
|
+
"q": int.from_bytes(obj[Attribute.SUBPRIME], byteorder="big"),
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return asn1.dump()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def encode_dsa_public_key(key: PublicKey) -> bytes:
|
|
56
|
+
"""
|
|
57
|
+
Encode DSA public key into RFC 3279 DER-encoded format.
|
|
58
|
+
|
|
59
|
+
:param PublicKey key: public key
|
|
60
|
+
:rtype: bytes
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
asn1 = Integer(int.from_bytes(key[Attribute.VALUE], byteorder="big"))
|
|
64
|
+
|
|
65
|
+
return asn1.dump()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def decode_dsa_public_key(der: bytes) -> bytes:
|
|
69
|
+
"""
|
|
70
|
+
Decode a DSA public key from RFC 3279 DER-encoded format.
|
|
71
|
+
|
|
72
|
+
Returns a `biginteger` encoded as bytes.
|
|
73
|
+
|
|
74
|
+
:param bytes der: DER-encoded public key
|
|
75
|
+
:rtype: bytes
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
asn1 = Integer.load(der)
|
|
79
|
+
|
|
80
|
+
return biginteger(asn1)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def encode_dsa_signature(signature: bytes) -> bytes:
|
|
84
|
+
"""
|
|
85
|
+
Encode a signature (generated by :meth:`pkcs11.SignMixin.sign`) into
|
|
86
|
+
DER-encoded ASN.1 (Dss_Sig_Value) format.
|
|
87
|
+
|
|
88
|
+
:param bytes signature: signature as bytes
|
|
89
|
+
:rtype: bytes
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
asn1 = DSASignature.from_p1363(signature)
|
|
93
|
+
|
|
94
|
+
return asn1.dump()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def decode_dsa_signature(der: bytes) -> bytes:
|
|
98
|
+
"""
|
|
99
|
+
Decode a DER-encoded ASN.1 (Dss_Sig_Value) signature (as generated by
|
|
100
|
+
OpenSSL/X.509) into PKCS #11 format.
|
|
101
|
+
|
|
102
|
+
:param bytes der: DER-encoded signature
|
|
103
|
+
:rtype bytes:
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
asn1 = DSASignature.load(der)
|
|
107
|
+
|
|
108
|
+
return asn1.to_p1363()
|
pkcs11/util/ec.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Key handling utilities for EC keys (ANSI X.62/RFC3279), domain parameter and
|
|
3
|
+
signatures.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
|
+
|
|
10
|
+
from asn1crypto.algos import DSASignature
|
|
11
|
+
from asn1crypto.core import OctetString
|
|
12
|
+
from asn1crypto.keys import (
|
|
13
|
+
ECDomainParameters,
|
|
14
|
+
ECPrivateKey,
|
|
15
|
+
NamedCurve,
|
|
16
|
+
PublicKeyInfo,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from pkcs11.constants import Attribute, ObjectClass
|
|
20
|
+
from pkcs11.mechanisms import KeyType
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from pkcs11.types import PublicKey
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def encode_named_curve_parameters(oid: str) -> bytes:
|
|
27
|
+
"""
|
|
28
|
+
Return DER-encoded ANSI X.62 EC parameters for a named curve.
|
|
29
|
+
|
|
30
|
+
Curve names are given by object identifier or common name. Names come
|
|
31
|
+
from `asn1crypto
|
|
32
|
+
<https://github.com/wbond/asn1crypto/blob/master/asn1crypto/keys.py#L338>`_.
|
|
33
|
+
|
|
34
|
+
:param str oid: OID or named curve
|
|
35
|
+
:rtype: bytes
|
|
36
|
+
"""
|
|
37
|
+
return ECDomainParameters(
|
|
38
|
+
name="named",
|
|
39
|
+
value=NamedCurve.unmap(oid),
|
|
40
|
+
).dump()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def decode_ec_public_key(
|
|
44
|
+
der: bytes,
|
|
45
|
+
encode_ec_point: bool = True,
|
|
46
|
+
) -> dict[Attribute, Any]:
|
|
47
|
+
"""
|
|
48
|
+
Decode a DER-encoded EC public key as stored by OpenSSL into a dictionary
|
|
49
|
+
of attributes able to be passed to :meth:`pkcs11.Session.create_object`.
|
|
50
|
+
|
|
51
|
+
.. note:: **encode_ec_point**
|
|
52
|
+
|
|
53
|
+
For use as an attribute `EC_POINT` should be DER-encoded (True).
|
|
54
|
+
|
|
55
|
+
For key derivation implementations can vary. Since v2.30 the
|
|
56
|
+
specification says implementations MUST accept a raw `EC_POINT` for
|
|
57
|
+
ECDH (False), however not all implementations follow this yet.
|
|
58
|
+
|
|
59
|
+
:param bytes der: DER-encoded key
|
|
60
|
+
:param encode_ec_point: See text.
|
|
61
|
+
:rtype: dict(Attribute,*)
|
|
62
|
+
"""
|
|
63
|
+
asn1 = PublicKeyInfo.load(der)
|
|
64
|
+
|
|
65
|
+
assert asn1.algorithm == "ec", "Wrong algorithm, not an EC key!"
|
|
66
|
+
|
|
67
|
+
ecpoint = bytes(asn1["public_key"])
|
|
68
|
+
|
|
69
|
+
if encode_ec_point:
|
|
70
|
+
ecpoint = OctetString(ecpoint).dump()
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
Attribute.KEY_TYPE: KeyType.EC,
|
|
74
|
+
Attribute.CLASS: ObjectClass.PUBLIC_KEY,
|
|
75
|
+
Attribute.EC_PARAMS: asn1["algorithm"]["parameters"].dump(),
|
|
76
|
+
Attribute.EC_POINT: ecpoint,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def decode_ec_private_key(der: bytes) -> dict[Attribute, Any]:
|
|
81
|
+
"""
|
|
82
|
+
Decode a DER-encoded EC private key as stored by OpenSSL into a dictionary
|
|
83
|
+
of attributes able to be passed to :meth:`pkcs11.Session.create_object`.
|
|
84
|
+
|
|
85
|
+
:param bytes der: DER-encoded key
|
|
86
|
+
:rtype: dict(Attribute,*)
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
asn1 = ECPrivateKey.load(der)
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
Attribute.KEY_TYPE: KeyType.EC,
|
|
93
|
+
Attribute.CLASS: ObjectClass.PRIVATE_KEY,
|
|
94
|
+
Attribute.EC_PARAMS: asn1["parameters"].chosen.dump(),
|
|
95
|
+
Attribute.VALUE: asn1["private_key"].contents,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def encode_ec_public_key(key: PublicKey) -> bytes:
|
|
100
|
+
"""
|
|
101
|
+
Encode a DER-encoded EC public key as stored by OpenSSL.
|
|
102
|
+
|
|
103
|
+
:param PublicKey key: EC public key
|
|
104
|
+
:rtype: bytes
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
ecparams = ECDomainParameters.load(key[Attribute.EC_PARAMS])
|
|
108
|
+
ecpoint = bytes(OctetString.load(key[Attribute.EC_POINT]))
|
|
109
|
+
|
|
110
|
+
return PublicKeyInfo(
|
|
111
|
+
{
|
|
112
|
+
"algorithm": {
|
|
113
|
+
"algorithm": "ec",
|
|
114
|
+
"parameters": ecparams,
|
|
115
|
+
},
|
|
116
|
+
"public_key": ecpoint,
|
|
117
|
+
}
|
|
118
|
+
).dump()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def encode_ecdsa_signature(signature: bytes) -> bytes:
|
|
122
|
+
"""
|
|
123
|
+
Encode a signature (generated by :meth:`pkcs11.SignMixin.sign`) into
|
|
124
|
+
DER-encoded ASN.1 (ECDSA_Sig_Value) format.
|
|
125
|
+
|
|
126
|
+
:param bytes signature: signature as bytes
|
|
127
|
+
:rtype: bytes
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
return DSASignature.from_p1363(signature).dump()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def decode_ecdsa_signature(der: bytes) -> bytes:
|
|
134
|
+
"""
|
|
135
|
+
Decode a DER-encoded ASN.1 (ECDSA_Sig_Value) signature (as generated by
|
|
136
|
+
OpenSSL/X.509) into PKCS #11 format.
|
|
137
|
+
|
|
138
|
+
:param bytes der: DER-encoded signature
|
|
139
|
+
:rtype bytes:
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
asn1 = DSASignature.load(der)
|
|
143
|
+
return asn1.to_p1363()
|
pkcs11/util/rsa.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Key handling utilities for RSA keys (PKCS#1).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
from asn1crypto.keys import RSAPrivateKey, RSAPublicKey
|
|
10
|
+
|
|
11
|
+
from pkcs11.constants import Attribute, MechanismFlag, ObjectClass
|
|
12
|
+
from pkcs11.defaults import DEFAULT_KEY_CAPABILITIES
|
|
13
|
+
from pkcs11.mechanisms import KeyType
|
|
14
|
+
from pkcs11.util import biginteger
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from pkcs11.types import PublicKey
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def decode_rsa_private_key(
|
|
21
|
+
der: bytes,
|
|
22
|
+
capabilities: MechanismFlag | int | None = None,
|
|
23
|
+
) -> dict[Attribute, Any]:
|
|
24
|
+
"""
|
|
25
|
+
Decode a RFC2437 (PKCS#1) DER-encoded RSA private key into a dictionary of
|
|
26
|
+
attributes able to be passed to :meth:`pkcs11.Session.create_object`.
|
|
27
|
+
|
|
28
|
+
:param bytes der: DER-encoded key
|
|
29
|
+
:param MechanismFlag capabilities: Optional key capabilities
|
|
30
|
+
:rtype: dict(Attribute,*)
|
|
31
|
+
"""
|
|
32
|
+
caps: MechanismFlag | int = (
|
|
33
|
+
DEFAULT_KEY_CAPABILITIES[KeyType.RSA] if capabilities is None else capabilities
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
key = RSAPrivateKey.load(der)
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
Attribute.CLASS: ObjectClass.PRIVATE_KEY,
|
|
40
|
+
Attribute.KEY_TYPE: KeyType.RSA,
|
|
41
|
+
Attribute.MODULUS: biginteger(key["modulus"]),
|
|
42
|
+
Attribute.PUBLIC_EXPONENT: biginteger(key["public_exponent"]),
|
|
43
|
+
Attribute.PRIVATE_EXPONENT: biginteger(key["private_exponent"]),
|
|
44
|
+
Attribute.PRIME_1: biginteger(key["prime1"]),
|
|
45
|
+
Attribute.PRIME_2: biginteger(key["prime2"]),
|
|
46
|
+
Attribute.EXPONENT_1: biginteger(key["exponent1"]),
|
|
47
|
+
Attribute.EXPONENT_2: biginteger(key["exponent2"]),
|
|
48
|
+
Attribute.COEFFICIENT: biginteger(key["coefficient"]),
|
|
49
|
+
Attribute.DECRYPT: MechanismFlag.DECRYPT & caps != 0,
|
|
50
|
+
Attribute.SIGN: MechanismFlag.SIGN & caps != 0,
|
|
51
|
+
Attribute.UNWRAP: MechanismFlag.UNWRAP & caps != 0,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def decode_rsa_public_key(
|
|
56
|
+
der: bytes,
|
|
57
|
+
capabilities: MechanismFlag | int | None = None,
|
|
58
|
+
) -> dict[Attribute, Any]:
|
|
59
|
+
"""
|
|
60
|
+
Decode a RFC2437 (PKCS#1) DER-encoded RSA public key into a dictionary of
|
|
61
|
+
attributes able to be passed to :meth:`pkcs11.Session.create_object`.
|
|
62
|
+
|
|
63
|
+
:param bytes der: DER-encoded key
|
|
64
|
+
:param MechanismFlag capabilities: Optional key capabilities
|
|
65
|
+
:rtype: dict(Attribute,*)
|
|
66
|
+
"""
|
|
67
|
+
caps: MechanismFlag | int = (
|
|
68
|
+
DEFAULT_KEY_CAPABILITIES[KeyType.RSA] if capabilities is None else capabilities
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
key = RSAPublicKey.load(der)
|
|
72
|
+
return {
|
|
73
|
+
Attribute.CLASS: ObjectClass.PUBLIC_KEY,
|
|
74
|
+
Attribute.KEY_TYPE: KeyType.RSA,
|
|
75
|
+
Attribute.MODULUS: biginteger(key["modulus"]),
|
|
76
|
+
Attribute.PUBLIC_EXPONENT: biginteger(key["public_exponent"]),
|
|
77
|
+
Attribute.ENCRYPT: MechanismFlag.ENCRYPT & caps != 0,
|
|
78
|
+
Attribute.VERIFY: MechanismFlag.VERIFY & caps != 0,
|
|
79
|
+
Attribute.WRAP: MechanismFlag.WRAP & caps != 0,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def encode_rsa_public_key(key: PublicKey) -> bytes:
|
|
84
|
+
"""
|
|
85
|
+
Encode an RSA public key into PKCS#1 DER-encoded format.
|
|
86
|
+
|
|
87
|
+
:param PublicKey key: RSA public key
|
|
88
|
+
:rtype: bytes
|
|
89
|
+
"""
|
|
90
|
+
return RSAPublicKey(
|
|
91
|
+
{
|
|
92
|
+
"modulus": int.from_bytes(key[Attribute.MODULUS], byteorder="big"),
|
|
93
|
+
"public_exponent": int.from_bytes(key[Attribute.PUBLIC_EXPONENT], byteorder="big"),
|
|
94
|
+
}
|
|
95
|
+
).dump()
|
pkcs11/util/x509.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Certificate handling utilities for X.509 (SSL) certificates.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from asn1crypto.core import OctetString
|
|
10
|
+
from asn1crypto.x509 import Certificate
|
|
11
|
+
|
|
12
|
+
from pkcs11.constants import Attribute, CertificateType, ObjectClass
|
|
13
|
+
from pkcs11.mechanisms import KeyType
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def decode_x509_public_key(der: bytes) -> dict[Attribute, Any]:
|
|
17
|
+
"""
|
|
18
|
+
Decode a DER-encoded X.509 certificate's public key into a set of
|
|
19
|
+
attributes able to be passed to :meth:`pkcs11.Session.create_object`.
|
|
20
|
+
|
|
21
|
+
For PEM-encoded certificates, use :func:`asn1crypto.pem.unarmor`.
|
|
22
|
+
|
|
23
|
+
.. warning::
|
|
24
|
+
|
|
25
|
+
Does not verify certificate.
|
|
26
|
+
|
|
27
|
+
:param bytes der: DER-encoded certificate
|
|
28
|
+
:rtype: dict(Attribute,*)
|
|
29
|
+
"""
|
|
30
|
+
x509 = Certificate.load(der)
|
|
31
|
+
key_info = x509.public_key
|
|
32
|
+
key = bytes(key_info["public_key"])
|
|
33
|
+
|
|
34
|
+
key_type = {
|
|
35
|
+
"rsa": KeyType.RSA,
|
|
36
|
+
"dsa": KeyType.DSA,
|
|
37
|
+
"ec": KeyType.EC,
|
|
38
|
+
}[key_info.algorithm]
|
|
39
|
+
|
|
40
|
+
attrs: dict[Attribute, Any] = {
|
|
41
|
+
Attribute.CLASS: ObjectClass.PUBLIC_KEY,
|
|
42
|
+
Attribute.KEY_TYPE: key_type,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if key_type is KeyType.RSA:
|
|
46
|
+
from .rsa import decode_rsa_public_key
|
|
47
|
+
|
|
48
|
+
attrs.update(decode_rsa_public_key(key))
|
|
49
|
+
elif key_type is KeyType.DSA:
|
|
50
|
+
from .dsa import decode_dsa_domain_parameters, decode_dsa_public_key
|
|
51
|
+
|
|
52
|
+
params = key_info["algorithm"]["parameters"].dump()
|
|
53
|
+
|
|
54
|
+
attrs.update(decode_dsa_domain_parameters(params))
|
|
55
|
+
attrs.update(
|
|
56
|
+
{
|
|
57
|
+
Attribute.VALUE: decode_dsa_public_key(key),
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
elif key_type is KeyType.EC:
|
|
61
|
+
params = key_info["algorithm"]["parameters"].dump()
|
|
62
|
+
|
|
63
|
+
# bytes(key_info['public_key']) returns the binary encoding
|
|
64
|
+
# of the EC point itself (decoded from its BitString representation in X.509),
|
|
65
|
+
# but PKCS#11 expects this as a DER OctetString.
|
|
66
|
+
key = OctetString(key).dump()
|
|
67
|
+
attrs.update(
|
|
68
|
+
{
|
|
69
|
+
Attribute.EC_PARAMS: params,
|
|
70
|
+
Attribute.EC_POINT: key,
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
raise AssertionError("Should not be reached")
|
|
75
|
+
|
|
76
|
+
return attrs
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def decode_x509_certificate(
|
|
80
|
+
der: bytes,
|
|
81
|
+
extended_set: bool = False,
|
|
82
|
+
) -> dict[Attribute, Any]:
|
|
83
|
+
"""
|
|
84
|
+
Decode a DER-encoded X.509 certificate into a dictionary of
|
|
85
|
+
attributes able to be passed to :meth:`pkcs11.Session.create_object`.
|
|
86
|
+
|
|
87
|
+
Optionally pass `extended_set` to include additional attributes:
|
|
88
|
+
start date, end date and key identifiers.
|
|
89
|
+
|
|
90
|
+
For PEM-encoded certificates, use :func:`asn1crypto.pem.unarmor`.
|
|
91
|
+
|
|
92
|
+
.. warning::
|
|
93
|
+
|
|
94
|
+
Does not verify certificate.
|
|
95
|
+
|
|
96
|
+
:param bytes der: DER-encoded certificate
|
|
97
|
+
:param extended_set: decodes more metadata about the certificate
|
|
98
|
+
:rtype: dict(Attribute,*)
|
|
99
|
+
"""
|
|
100
|
+
x509 = Certificate.load(der)
|
|
101
|
+
subject = x509.subject
|
|
102
|
+
issuer = x509.issuer
|
|
103
|
+
serial = x509["tbs_certificate"]["serial_number"]
|
|
104
|
+
|
|
105
|
+
template: dict[Attribute, Any] = {
|
|
106
|
+
Attribute.CLASS: ObjectClass.CERTIFICATE,
|
|
107
|
+
Attribute.CERTIFICATE_TYPE: CertificateType.X_509,
|
|
108
|
+
Attribute.SUBJECT: subject.dump(),
|
|
109
|
+
Attribute.ISSUER: issuer.dump(),
|
|
110
|
+
Attribute.SERIAL_NUMBER: serial.dump(),
|
|
111
|
+
Attribute.VALUE: x509.dump(),
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if extended_set:
|
|
115
|
+
start_date = x509["tbs_certificate"]["validity"]["not_before"].native.date()
|
|
116
|
+
end_date = x509["tbs_certificate"]["validity"]["not_after"].native.date()
|
|
117
|
+
|
|
118
|
+
template.update(
|
|
119
|
+
{
|
|
120
|
+
Attribute.START_DATE: start_date,
|
|
121
|
+
Attribute.END_DATE: end_date,
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# FIXME: is this correct?
|
|
126
|
+
try:
|
|
127
|
+
template[Attribute.HASH_OF_SUBJECT_PUBLIC_KEY] = x509.key_identifier
|
|
128
|
+
except KeyError:
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
template[Attribute.HASH_OF_ISSUER_PUBLIC_KEY] = x509.authority_key_identifier
|
|
133
|
+
except KeyError:
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
return template
|