Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: bugs with non RSA keys signing #128

Merged
merged 8 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make signing more consistent using the same types
  • Loading branch information
fulder committed Mar 23, 2024
commit aaa0d922b4a0edb3a5f4202f9783514d30899c3d
2 changes: 1 addition & 1 deletion docs/examples/src/ocsp/response/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
revocation_time=datetime.datetime.now(),
)

res.sign(cert, cert, SHA512.algorithm, cert_key_pair.private_key)
res.sign(cert, cert, SHA512, cert_key_pair.private_key, SHA512)

print(res)
21 changes: 13 additions & 8 deletions pki_tools/types/certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,17 @@ def from_cryptography(
if cert.extensions:
extensions = Extensions.from_cryptography(cert.extensions)

signature_algorithm = None
if cert.signature_hash_algorithm:
signature_algorithm = SignatureAlgorithm.from_cryptography(
cert.signature_hash_algorithm,
cert.signature_algorithm_parameters,
)

ret = cls(
version=cert.version.value,
serial_number=cert.serial_number,
signature_algorithm=SignatureAlgorithm.from_cryptography(
cert.signature_hash_algorithm,
cert.signature_algorithm_parameters,
),
signature_algorithm=signature_algorithm,
issuer=Name.from_cryptography(cert.issuer),
validity=Validity(
not_before=cert.not_valid_before_utc,
Expand Down Expand Up @@ -356,7 +360,7 @@ def verify_signature(
def sign(
self,
key_pair: CryptoKeyPair,
signature_algorithm: SignatureAlgorithm,
signature_algorithm: Optional[SignatureAlgorithm] = None,
req_key: Optional[CryptoPublicKey] = None,
) -> None:
"""
Expand Down Expand Up @@ -427,13 +431,14 @@ def _to_cryptography(self) -> x509.Certificate:
extension._to_cryptography(), extension.critical
)

alg = self.signature_algorithm.algorithm._to_cryptography()
if isinstance(self.subject_public_key_info.algorithm, Ed448PublicKey):
alg = None
if isinstance(
self.subject_public_key_info.algorithm, Ed448PublicKey
) or isinstance(
self.subject_public_key_info.algorithm, Ed25519PublicKey
):
alg = None
else:
alg = self.signature_algorithm.algorithm._to_cryptography()

cert = cert_builder.sign(crypto_key, alg)

Expand Down
25 changes: 19 additions & 6 deletions pki_tools/types/crl.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@

from pki_tools.types.extensions import Extensions
from pki_tools.exceptions import MissingInit, LoadError
from pki_tools.types.key_pair import CryptoPrivateKey
from pki_tools.types.key_pair import (
CryptoPrivateKey,
Ed25519PrivateKey,
Ed448PrivateKey,
)
from pki_tools.types.crypto_parser import (
CryptoParser,
InitCryptoParser,
CryptoConfig,
HelperFunc,
)
from pki_tools.types.name import Name
from pki_tools.types.signature_algorithm import HashAlgorithm
from pki_tools.types.signature_algorithm import SignatureAlgorithm
from pki_tools.types.utils import (
CACHE_TIME_SECONDS,
CertsUri,
Expand Down Expand Up @@ -182,17 +186,19 @@ def tbs_bytes(self) -> bytes:
return self._crypto_object.tbs_certlist_bytes

def sign(
self, private_key: CryptoPrivateKey, algorithm: HashAlgorithm
self,
private_key: CryptoPrivateKey,
algorithm: Optional[SignatureAlgorithm] = None,
) -> None:
"""
Sign the CRL with the provided private key and algorithm.

Args:
private_key: Private key used to sign the CRL.
algorithm: Hash algorithm to use for signing.
algorithm: Signature algorithm to use for signing.
"""
self._private_key = private_key
self._algorithm = algorithm
self._signature_algorithm = algorithm
self._x509_obj = self._to_cryptography()

def get_revoked(self, cert_serial: int) -> Optional[RevokedCertificate]:
Expand Down Expand Up @@ -226,9 +232,16 @@ def _to_cryptography(self) -> x509.CertificateRevocationList:
for cert in self.revoked_certs:
builder = builder.add_revoked_certificate(cert._to_cryptography())

if isinstance(self._private_key, Ed25519PrivateKey) or isinstance(
self._private_key, Ed448PrivateKey
):
alg = None
else:
alg = self._signature_algorithm.algorithm._to_cryptography()

return builder.sign(
private_key=self._private_key._to_cryptography(),
algorithm=self._algorithm._to_cryptography(),
algorithm=alg,
)

def _string_dict(self) -> Dict[str, str]:
Expand Down
28 changes: 19 additions & 9 deletions pki_tools/types/csr.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
CryptoPublicKey,
CryptoPrivateKey,
CryptoKeyPair,
Ed25519PrivateKey,
Ed448PrivateKey,
)
from pki_tools.types.crypto_parser import (
InitCryptoParser,
Expand Down Expand Up @@ -72,13 +74,17 @@ def from_cryptography(
for att in crypto_csr.attributes:
attributes[att.oid.dotted_string] = att.value

signature_algorithm = None
if crypto_csr.signature_hash_algorithm:
signature_algorithm = SignatureAlgorithm.from_cryptography(
crypto_csr.signature_hash_algorithm,
crypto_csr.signature_algorithm_parameters,
)

ret = cls(
subject=Name.from_cryptography(crypto_csr.subject),
extensions=Extensions.from_cryptography(crypto_csr.extensions),
signature_algorithm=SignatureAlgorithm.from_cryptography(
crypto_csr.signature_hash_algorithm,
crypto_csr.signature_algorithm_parameters,
),
signature_algorithm=signature_algorithm,
signature_value=_byte_to_hex(crypto_csr.signature),
public_key=CryptoPublicKey.from_cryptography(
crypto_csr.public_key()
Expand Down Expand Up @@ -114,7 +120,7 @@ def pem_bytes(self) -> bytes:
def sign(
self,
key_pair: CryptoKeyPair,
signature_algorithm: SignatureAlgorithm,
signature_algorithm: Optional[SignatureAlgorithm] = None,
):
"""
Sign the CSR with the provided key pair and signature algorithm.
Expand Down Expand Up @@ -178,10 +184,14 @@ def _to_cryptography(self) -> x509.CertificateSigningRequest:
oid = x509.ObjectIdentifier(attribute_oid)
builder = builder.add_attribute(oid, value)

return builder.sign(
crypto_key,
self.signature_algorithm.algorithm._to_cryptography(),
)
if isinstance(self._private_key, Ed448PrivateKey) or isinstance(
self._private_key, Ed25519PrivateKey
):
alg = None
else:
alg = self.signature_algorithm.algorithm._to_cryptography()

return builder.sign(crypto_key, alg)

def __str__(self) -> str:
return yaml.safe_dump(
Expand Down
35 changes: 28 additions & 7 deletions pki_tools/types/key_pair.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,14 @@ def pem_bytes(self) -> bytes:
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

def verify(self, signed: InitCryptoParser):
self._crypto_object.verify(
signed._crypto_object.signature,
signed.tbs_bytes,
PKCS1v15Padding()._to_cryptography(),
signed._crypto_object.signature_hash_algorithm,
)
@abc.abstractmethod
def verify(self, signed: InitCryptoParser) -> None:
"""
Verifies the signature of a signed object.

Args:
signed: the signed object to verify.
"""

@classmethod
def _crypto_config(cls) -> CryptoConfig:
Expand Down Expand Up @@ -545,6 +546,14 @@ def der_bytes(self) -> bytes:
format=PublicFormat.PKCS1,
)

def verify(self, signed: InitCryptoParser) -> None:
return self._crypto_object.verify(
signed._crypto_object.signature,
signed.tbs_bytes,
PKCS1v15Padding()._to_cryptography(),
signed._crypto_object.signature_hash_algorithm,
)

def _to_cryptography(self) -> rsa.RSAPublicKey:
public_numbers = rsa.RSAPublicNumbers(e=self.e, n=self.n)

Expand Down Expand Up @@ -857,6 +866,12 @@ def from_cryptography(
ret._x509_obj = key
return ret

def verify(self, signed: InitCryptoParser):
self._crypto_object.verify(
signed._crypto_object.signature,
signed.tbs_bytes,
)

def _to_cryptography(
self,
) -> ed448.Ed448PublicKey:
Expand Down Expand Up @@ -961,6 +976,12 @@ def from_cryptography(
ret._x509_obj = key
return ret

def verify(self, signed: InitCryptoParser):
self._crypto_object.verify(
signed._crypto_object.signature,
signed.tbs_bytes,
)

def _to_cryptography(
self,
) -> ed25519.Ed25519PublicKey:
Expand Down
30 changes: 22 additions & 8 deletions pki_tools/types/ocsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@
from pki_tools.exceptions import (
MissingInit,
)
from pki_tools.types.key_pair import CryptoPrivateKey
from pki_tools.types.key_pair import (
CryptoPrivateKey,
Ed25519PrivateKey,
Ed448PrivateKey,
)
from pki_tools.types.crypto_parser import (
InitCryptoParser,
CryptoConfig,
HelperFunc,
)
from pki_tools.types.signature_algorithm import HashAlgorithm
from pki_tools.types.signature_algorithm import HashAlgorithm, \
SignatureAlgorithm
from pki_tools.types.utils import _byte_to_hex


Expand Down Expand Up @@ -189,24 +194,26 @@ def sign(
self,
cert: Certificate,
issuer: Certificate,
algorithm: HashAlgorithm,
response_algorithm: SignatureAlgorithm,
private_key: CryptoPrivateKey,
signature_algorithm: Optional[SignatureAlgorithm] = None,
):
"""
Signs the OCSP response.

Args:
cert: The certificate.
issuer: The issuer certificate.
algorithm: The hash algorithm.
response_algorithm: The signature algorithm for the response.
private_key: The private key to sign the response.
signature_algorithm: The signature algorithm.
"""
self._cert = cert
self._issuer = issuer
self._algorithm = algorithm
self._response_algorithm = response_algorithm
self._private_key = private_key
self._signature_algorithm = signature_algorithm
self._x509_obj = self._to_cryptography()
# self.issuer_key_hash = self.hash_with_alg(issuer.der_public_key)

def _to_cryptography(self) -> ocsp.OCSPResponse:
if not hasattr(self, "_private_key"):
Expand All @@ -222,7 +229,7 @@ def _to_cryptography(self) -> ocsp.OCSPResponse:
builder = builder.add_response(
cert=self._cert._to_cryptography(),
issuer=self._issuer._to_cryptography(),
algorithm=self._algorithm._to_cryptography(),
algorithm=self._response_algorithm.algorithm._to_cryptography(),
cert_status=cert_status,
this_update=datetime.now(),
next_update=datetime.now(),
Expand All @@ -232,9 +239,16 @@ def _to_cryptography(self) -> ocsp.OCSPResponse:
ocsp.OCSPResponderEncoding.HASH, self._cert._to_cryptography()
)

if isinstance(self._private_key, Ed25519PrivateKey) or isinstance(
self._private_key, Ed448PrivateKey
):
alg = None
else:
alg = self._signature_algorithm.algorithm._to_cryptography()

return builder.sign(
self._private_key._to_cryptography(),
self._algorithm._to_cryptography(),
alg,
)

def _string_dict(self) -> Dict[str, str]:
Expand Down