Skip to content

Commit 33b5c88

Browse files
committed
Add PKCS#8 support to outputting SigningKeys
1 parent 872332a commit 33b5c88

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

src/ecdsa/keys.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ def from_der(cls, string, hashfunc=sha1):
970970

971971
if algorithm_oid not in (oid_ecPublicKey, oid_ecDH, oid_ecMQV):
972972
raise der.UnexpectedDER(
973-
"unexpected algorithm identifier '%s'" % algorithm_oid
973+
"unexpected algorithm identifier '%s'" % (algorithm_oid,)
974974
)
975975
if empty != b"":
976976
raise der.UnexpectedDER(
@@ -1049,7 +1049,7 @@ def to_string(self):
10491049
s = number_to_string(secexp, self.privkey.order)
10501050
return s
10511051

1052-
def to_pem(self, point_encoding="uncompressed"):
1052+
def to_pem(self, point_encoding="uncompressed", format="sslay"):
10531053
"""
10541054
Convert the private key to the :term:`PEM` format.
10551055
@@ -1058,9 +1058,11 @@ def to_pem(self, point_encoding="uncompressed"):
10581058
Only the named curve format is supported.
10591059
The public key will be included in generated string.
10601060
1061-
The PEM header will specify ``BEGIN EC PRIVATE KEY``
1061+
The PEM header will specify ``BEGIN EC PRIVATE KEY`` or
1062+
``BEGIN PRIVATE KEY``, depending on the desired format.
10621063
10631064
:param str point_encoding: format to use for encoding public point
1065+
:param str format: either `sslay` or `pkcs8`
10641066
10651067
:return: PEM encoded private key
10661068
:rtype: bytes
@@ -1069,9 +1071,11 @@ def to_pem(self, point_encoding="uncompressed"):
10691071
re-encoded if the system is incompatible (e.g. uses UTF-16)
10701072
"""
10711073
# TODO: "BEGIN ECPARAMETERS"
1072-
return der.topem(self.to_der(point_encoding), "EC PRIVATE KEY")
1074+
assert format in ("sslay", "pkcs8")
1075+
header = "EC PRIVATE KEY" if format == "sslay" else "PRIVATE KEY"
1076+
return der.topem(self.to_der(point_encoding, format), header)
10731077

1074-
def to_der(self, point_encoding="uncompressed"):
1078+
def to_der(self, point_encoding="uncompressed", format="sslay"):
10751079
"""
10761080
Convert the private key to the :term:`DER` format.
10771081
@@ -1081,6 +1085,7 @@ def to_der(self, point_encoding="uncompressed"):
10811085
The public key will be included in the generated string.
10821086
10831087
:param str point_encoding: format to use for encoding public point
1088+
:param str format: either `sslay` or `pkcs8`
10841089
10851090
:return: DER encoded private key
10861091
:rtype: bytes
@@ -1089,16 +1094,30 @@ def to_der(self, point_encoding="uncompressed"):
10891094
# cont[1],bitstring])
10901095
if point_encoding == "raw":
10911096
raise ValueError("raw encoding not allowed in DER")
1097+
assert format in ("sslay", "pkcs8")
10921098
encoded_vk = self.get_verifying_key().to_string(point_encoding)
10931099
# the 0 in encode_bitstring specifies the number of unused bits
10941100
# in the `encoded_vk` string
1095-
return der.encode_sequence(
1101+
ec_private_key = der.encode_sequence(
10961102
der.encode_integer(1),
10971103
der.encode_octet_string(self.to_string()),
10981104
der.encode_constructed(0, self.curve.encoded_oid),
10991105
der.encode_constructed(1, der.encode_bitstring(encoded_vk, 0)),
11001106
)
11011107

1108+
if format == "sslay":
1109+
return ec_private_key
1110+
else:
1111+
return der.encode_sequence(
1112+
# version = 1 means the public key is not present in the
1113+
# top-level structure.
1114+
der.encode_integer(1),
1115+
der.encode_sequence(
1116+
der.encode_oid(*oid_ecPublicKey), self.curve.encoded_oid
1117+
),
1118+
der.encode_octet_string(ec_private_key),
1119+
)
1120+
11021121
def get_verifying_key(self):
11031122
"""
11041123
Return the VerifyingKey associated with this private key.

0 commit comments

Comments
 (0)