Skip to content

Commit a0c2697

Browse files
committed
Change API
Signed-off-by: laurentsimon <laurentsimon@google.com>
1 parent 64822e6 commit a0c2697

File tree

5 files changed

+77
-42
lines changed

5 files changed

+77
-42
lines changed

sigstore/_utils.py

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,23 @@
2323
import sys
2424
from typing import IO, NewType, Union
2525

26-
from cryptography.hazmat.primitives import hashes, serialization
26+
from cryptography.hazmat.primitives import serialization
2727
from cryptography.hazmat.primitives.asymmetric import ec, rsa
28+
<<<<<<< HEAD
2829
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
2930
from cryptography.x509 import (
3031
Certificate,
3132
ExtensionNotFound,
3233
Version,
3334
load_der_x509_certificate,
3435
)
36+
=======
37+
from cryptography.x509 import Certificate, ExtensionNotFound, Version
38+
>>>>>>> f67b019 (Change API)
3539
from cryptography.x509.oid import ExtendedKeyUsageOID, ExtensionOID
3640
from sigstore_protobuf_specs.dev.sigstore.common.v1 import HashAlgorithm
3741

42+
from sigstore import hashes as sigstore_hashes
3843
from sigstore.errors import Error
3944

4045
if sys.version_info < (3, 11):
@@ -159,26 +164,13 @@ def key_id(key: PublicKey) -> KeyID:
159164

160165
return KeyID(hashlib.sha256(public_bytes).digest())
161166

162-
def hazmat_digest_to_bundle(algo: str) -> HashAlgorithm:
163-
lookup = {hashes.SHA256().name: HashAlgorithm.SHA2_256}
164-
if algo in lookup:
165-
return HashAlgorithm(lookup[algo])
166-
return ValueError(f"unknown digest algorithm {algo}")
167-
168-
def get_digest(
169-
input_: IO[bytes],
170-
algorithm_: Prehashed = None,
171-
) -> (bytes, Prehashed):
172-
if algorithm_ is None:
173-
return sha256_streaming(input_), Prehashed(hashes.SHA256())
174-
175-
if isinstance(algorithm_, Prehashed):
176-
# Check we have a 256-bit digest size for compatibility with secp256r1.
177-
if algorithm_.digest_size != 32:
178-
return ValueError(f"invalid digest size ({algorithm_.digest_size}), expected 32")
179-
return input_.getvalue(), algorithm_
180-
181-
raise ValueError("invalid arguments")
167+
def get_digest(input_: IO[bytes] | sigstore_hashes.Hashed) -> sigstore_hashes.Hashed:
168+
if isinstance(input_, sigstore_hashes.Hashed):
169+
return input_
170+
171+
# NOTE: Not able to check for the type `TypeError: Subscripted generics cannot be used with class and instance checks`
172+
# when calling isinstance(_input, IO[bytes])
173+
return sigstore_hashes.Hashed(digest=sha256_streaming(input_), algorithm=HashAlgorithm.SHA2_256)
182174

183175
def sha256_streaming(io: IO[bytes]) -> bytes:
184176
"""

sigstore/hashes.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
# Copyright 2023 The Sigstore Authors
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
from cryptography.hazmat.primitives import hashes
17+
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
18+
from pydantic import BaseModel
19+
from sigstore_protobuf_specs.dev.sigstore.common.v1 import HashAlgorithm
20+
21+
22+
class DIRSHA256_P1(hashes.HashAlgorithm):
23+
name = "dirsha256-p1"
24+
digest_size = 32
25+
block_size = -1
26+
27+
class Hashed(BaseModel):
28+
"""
29+
Represents hashed value.
30+
"""
31+
32+
algorithm: HashAlgorithm
33+
"""
34+
The digest algorithm uses to compute the digest.
35+
"""
36+
37+
digest: bytes
38+
"""
39+
The digest representing the hash value.
40+
"""
41+
42+
def as_prehashed(self) -> Prehashed:
43+
return Prehashed(self.hazmat_algorithm())
44+
45+
def hazmat_algorithm(self) -> hashes.HashAlgorithm:
46+
if self.algorithm == HashAlgorithm.SHA2_256:
47+
return hashes.SHA256()
48+
if self.algorithm == HashAlgorithm.HASH_ALGORITHM_UNSPECIFIED:
49+
return DIRSHA256_P1()
50+
raise ValueError(f"unknown hash algorithm: {self.algorithm}")

sigstore/sign.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@
4949
import rekor_types
5050
from cryptography.hazmat.primitives import hashes, serialization
5151
from cryptography.hazmat.primitives.asymmetric import ec
52-
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
5352
from cryptography.x509.oid import NameOID
5453
from in_toto_attestation.v1.statement import Statement
5554
from sigstore_protobuf_specs.dev.sigstore.bundle.v1 import (
5655
Bundle,
5756
VerificationMaterial,
5857
)
5958
from sigstore_protobuf_specs.dev.sigstore.common.v1 import (
59+
HashAlgorithm,
6060
HashOutput,
6161
LogId,
6262
MessageSignature,
@@ -73,6 +73,7 @@
7373
from sigstore_protobuf_specs.io.intoto import Envelope
7474

7575
from sigstore._internal import dsse
76+
from sigstore import hashes as sigstore_hashes
7677
from sigstore._internal.fulcio import (
7778
ExpiredCertificate,
7879
FulcioCertificateSigningResponse,

sigstore/verify/models.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
from typing import IO
2727

2828
import rekor_types
29-
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
3029
from cryptography.hazmat.primitives.serialization import Encoding
3130
from cryptography.x509 import (
3231
Certificate,
@@ -54,6 +53,7 @@
5453
TransparencyLogEntry,
5554
)
5655

56+
from sigstore import hashes as sigstore_hashes
5757
from sigstore._internal.rekor import RekorClient
5858
from sigstore._utils import (
5959
B64Str,
@@ -62,7 +62,6 @@
6262
cert_is_leaf,
6363
cert_is_root_ca,
6464
get_digest,
65-
hazmat_digest_to_bundle,
6665
)
6766
from sigstore.errors import Error
6867
from sigstore.transparency import LogEntry, LogInclusionProof
@@ -180,17 +179,11 @@ class VerificationMaterials:
180179
Represents the materials needed to perform a Sigstore verification.
181180
"""
182181

183-
digest_algorithm: Prehashed
182+
hashed_input: sigstore_hashes.Hashed
184183
"""
185-
The digest algorithm to use for the hash.
184+
The hash of the verification input.
186185
"""
187186

188-
input_digest: bytes
189-
"""
190-
The 'digest_algorithm' hash of the verification input, as raw bytes.
191-
"""
192-
193-
194187
certificate: Certificate
195188
"""
196189
The certificate that attests to and contains the public signing key.
@@ -234,12 +227,11 @@ class VerificationMaterials:
234227
def __init__(
235228
self,
236229
*,
237-
input_: IO[bytes],
230+
input_: IO[bytes] | sigstore_hashes.Hashed,
238231
cert_pem: PEMCert,
239232
signature: bytes,
240233
offline: bool = False,
241234
rekor_entry: LogEntry | None,
242-
algorithm_: Prehashed = None
243235
):
244236
"""
245237
Create a new `VerificationMaterials` from the given materials.
@@ -254,7 +246,7 @@ def __init__(
254246
Effect: `input_` is consumed as part of construction.
255247
"""
256248

257-
self.input_digest, self.digest_algorithm = get_digest(input_, algorithm_)
249+
self.hashed_input = get_digest(input_)
258250
self.certificate = load_pem_x509_certificate(cert_pem.encode())
259251
self.signature = signature
260252

@@ -424,8 +416,8 @@ def rekor_entry(self, client: RekorClient) -> LogEntry:
424416
),
425417
data=rekor_types.hashedrekord.Data(
426418
hash=rekor_types.hashedrekord.Hash(
427-
algorithm=self.digest_algorithm._algorithm.name,
428-
value=self.input_digest.hex(),
419+
algorithm=self.hashed_input.hazmat_algorithm().name,
420+
value=self.hashed_input.digest.hex(),
429421
),
430422
),
431423
),
@@ -518,8 +510,8 @@ def to_bundle(self) -> Bundle:
518510
),
519511
message_signature=MessageSignature(
520512
message_digest=HashOutput(
521-
algorithm=hazmat_digest_to_bundle(self.digest_algorithm._algorithm.name),
522-
digest=self.input_digest,
513+
algorithm=self.hashed_input.algorithm,
514+
digest=self.hashed_input.digest,
523515
),
524516
signature=self.signature,
525517
),

sigstore/verify/verifier.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ def verify(
223223
signing_key = cast(ec.EllipticCurvePublicKey, signing_key)
224224
signing_key.verify(
225225
materials.signature,
226-
materials.input_digest,
227-
ec.ECDSA(materials.digest_algorithm),
226+
materials.hashed_input.digest,
227+
ec.ECDSA(materials.hashed_input.as_prehashed()),
228228
)
229229
except InvalidSignature:
230230
return VerificationFailure(reason="Signature is invalid for input")
@@ -239,7 +239,7 @@ def verify(
239239
except RekorEntryMissingError:
240240
return LogEntryMissing(
241241
signature=B64Str(base64.b64encode(materials.signature).decode()),
242-
artifact_hash=HexStr(materials.input_digest.hex()),
242+
artifact_hash=HexStr(materials.hashed_input.digest.hex()),
243243
)
244244
except InvalidRekorEntryError:
245245
return VerificationFailure(

0 commit comments

Comments
 (0)