Repository: pyca/cryptography

Issue:
dsa.DSAPublicKey.verify is missing a return type annotation
Python version: 3.9.5/3.10.0b2 (though this appears in other Python versions)
PyCA version 3.4.7 (latest at the current time) on macOS, installed from pre-built wheels

I noticed that my call to dsa.DSAPublicKey.verify() was showing up in mypy as a coverage miss. Upon closer inspection, it seems like it is missing its return type annotation of "`-> None`":

```python
    @abc.abstractmethod
    def verify(
        self,
        signature: bytes,
        data: bytes,
        algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
    ):
        """
        Verifies the signature of the data.
        """
```

I'm also seeing coverage issues with the ec.ECDSAPrivateKey.sign() and ec.ECDSAPublicKey.verify() functions, but those appear to have proper type annotations so I'm still looking into what might be going on there.


Discussion:
Looking more closely, the additional coverage issues mentioned above are also missing annotations in a few places.

In hazmat/primitives/asymmetric/ed25519.py at around line 77, private_bytes() is missing a return type of `bytes`:

```python
    @abc.abstractmethod
    def private_bytes(
        self,
        encoding: _serialization.Encoding,
        format: _serialization.PrivateFormat,
        encryption_algorithm: _serialization.KeySerializationEncryption,
    ):
```

There's a similar problem in ed448.py at around line 78:

```python
    @abc.abstractmethod
    def private_bytes(
        self,
        encoding: _serialization.Encoding,
        format: _serialization.PrivateFormat,
        encryption_algorithm: _serialization.KeySerializationEncryption,
    ):
```

There's also a problem in ed448.py with the definition of verify() at around line 35, where the return type of `None` is missing:

```python
    @abc.abstractmethod
    def verify(self, signature: bytes, data: bytes):
```
There's another similar issue in hazmat/primitives/asymmetric/x448.py. At around line 14, from_public_bytes() is missing a type of `bytes` on its `data` argument:

```python
    @classmethod
    def from_public_bytes(cls, data) -> "X448PublicKey":
```
Looking at these they all appear to be fixed in `main`. We did quite a bit of additional typing work in https://github.com/pyca/cryptography/pull/5887 and some other PRs. Are there any you see still missing in current `main`?
Thanks for letting me know - my previous testing was against 3.4.7.

The issue with verify() for DSA keys does seem to be fixed in main, as are the issues I found in the Ed25519/Ed448 and X448 code.

I'm still seeing some uncovered code, but the problems are captured in other issues already - specifically #5824 and #6083.

I also got a type error in mypy after switching to main with code that previously worked, but it appears related to having type checking on the return value from x509.Extensions.get_extension_for_oid() now. It returns ExtensionType, so you basically need to downcast to a specific extension type before you access fields in what it returns. In my case, I was getting back an UnrecognizedExtension and wanted to access the raw value bytes, but "value" didn't exist in ExtensionType.

The original code was something like:

```python
            comment = cert.extensions.get_extension_for_oid(_nscomment_oid)
            comment_der = comment.value.value
```

I had to change it to the following to avoid the mypy error:

```python
            comment = cert.extensions.get_extension_for_oid(_nscomment_oid)
            comment_der = cast(x509.UnrecognizedExtension, comment.value).value
```

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py
--- a/src/cryptography/hazmat/backends/openssl/dsa.py
+++ b/src/cryptography/hazmat/backends/openssl/dsa.py
@@ -58,10 +58,10 @@ def __init__(self, backend, public_key, signature, algorithm):
 
         self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
 
-    def update(self, data):
+    def update(self, data: bytes):
         self._hash_ctx.update(data)
 
-    def verify(self):
+    def verify(self) -> None:
         data_to_verify = self._hash_ctx.finalize()
 
         _dsa_sig_verify(
@@ -282,7 +282,7 @@ def verify(
         signature: bytes,
         data: bytes,
         algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
-    ):
+    ) -> None:
         data, algorithm = _calculate_digest_and_algorithm(
             self._backend, data, algorithm
         )


Test patch: