Skip to content

Commit

Permalink
Continue project.
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkaMaul committed Sep 26, 2024
1 parent 845df89 commit fe0d083
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 24 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ build-backend = "maturin"
features = ["pyo3/extension-module"]
python-source = "src"
manifest-path = "rust/Cargo.toml"
module-name = "sigstore_tsp._rust"

[tool.ruff]
line-length = 100
Expand Down
64 changes: 55 additions & 9 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,42 @@ pub struct TimeStampResp {
}

#[pyo3::pymethods]
impl TimeStampResp {}
impl TimeStampResp {
#[getter]
fn status(&self) -> pyo3::PyResult<u8> {
Ok(self.raw.borrow_dependent().status.status)
}

#[getter]
fn status_string<'p>(
&self,
py: pyo3::Python<'p>,
) -> pyo3::PyResult<pyo3::Bound<'p, pyo3::types::PyList>> {
let opt_status_strings = &self.raw.borrow_dependent().status.status_string;
match opt_status_strings {
Some(status_strings) => {
let status_list = pyo3::types::PyList::empty_bound(py);
for status_string in status_strings.clone() {
let _ = status_list
.append(pyo3::types::PyString::new_bound(py, status_string.as_str()));
}
Ok(status_list)
}
None => {
return Err(pyo3::exceptions::PyNotImplementedError::new_err(
"No status string is not yet implemented.",
))
}
}
}

// #[getter]
// fn fail_info(
// &self,
// ) -> pyo3::PyResult<String> {
// Ok(self.raw.borrow_dependent().status.status)
// }
}

#[pyo3::pyfunction]
#[pyo3(signature = (data))]
Expand Down Expand Up @@ -123,14 +158,25 @@ pub(crate) fn create_timestamp_request(
}

/// A Python module implemented in Rust.
#[pymodule]
fn sigstore_tsp(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<TimeStampReq>()?;
m.add_class::<TimeStampResp>()?;
m.add_function(wrap_pyfunction!(parse_timestamp_response, m)?)?;
m.add_function(wrap_pyfunction!(create_timestamp_request, m)?)?;
m.add_function(wrap_pyfunction!(parse_timestamp_request, m)?)?;
Ok(())
#[pyo3::pymodule]
mod sigstore_tsp {

use super::*;

#[pyo3::pymodule]
mod _rust {

use super::*;

#[pymodule_export]
use super::parse_timestamp_response;

#[pymodule_export]
use super::create_timestamp_request;

#[pymodule_export]
use super::parse_timestamp_request;
}
}

#[cfg(test)]
Expand Down
6 changes: 3 additions & 3 deletions rust/src/tsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ pub struct RawTimeStampReq<'a> {
// failInfo PKIFailureInfo OPTIONAL }
#[derive(asn1::Asn1Read, asn1::Asn1Write)]
pub(crate) struct PKIStatusInfo<'a> {
status: u8,
status_string: Option<asn1::SequenceOf<'a, asn1::Utf8String<'a>>>,
fail_info: Option<asn1::BitString<'a>>,
pub status: u8,
pub status_string: Option<asn1::SequenceOf<'a, asn1::Utf8String<'a>>>,
pub fail_info: Option<asn1::BitString<'a>>,
}

// Accuracy ::= SEQUENCE {
Expand Down
12 changes: 12 additions & 0 deletions src/sigstore_tsp/_rust/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class TimeStampRequest: ...

def create_timestamp_request(
data: bytes,
) -> TimeStampRequest: ...


class TimeStampResponse: ...

def parse_timestamp_response(
data: bytes,
) -> TimeStampResponse: ...
96 changes: 84 additions & 12 deletions src/sigstore_tsp/base.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,98 @@
"""Base implementation."""

from __future__ import annotations

import enum

from sigstore_tsp import _rust


class HashAlgorithm(enum.Enum):
"""Hash algorithms."""

SHA512 = "SHA512"


_AllowedHashTypes = HashAlgorithm


class TimestampRequestBuilder:
def __init__(self, data: bytes| None = None, hash_algorithm: None = None, req_policy: None = None, nonce: int | None = None, cert_req : bool = False, extensions: None = None):
self._data = data
self._algorithm = hash_algorithm
"""Timestamp Request Builder class."""

def __init__(
self,
data: bytes | None = None,
hash_algorithm: _AllowedHashTypes | None = None,
req_policy: None | int = None,
cert_req: bool = False, # noqa: FBT001, FBT002
extensions: None = None,
) -> None:
"""Init method."""
self._data: bytes | None = data
self._algorithm: _AllowedHashTypes | None = hash_algorithm
self._req_policy = req_policy
self._nonce = nonce
self._cert_req = cert_req
self._cert_req: bool = cert_req
self._extensions = extensions

def data(self, data: bytes) -> TimestampRequestBuilder:
"""Set the data to be timestamped."""
if not data:
raise ValueError("The data to timestamp cannot be empty.")
msg = "The data to timestamp cannot be empty."
raise ValueError(msg)
if self._data is not None:
raise ValueError("The data may only be set once.")
msg = "The data may only be set once."
raise ValueError(msg)
return TimestampRequestBuilder(
data, self._algorithm, self._req_policy, self._nonce, self._cert_req, self._extensions
data, self._algorithm, self._req_policy, self._cert_req, self._extensions
)

def add_extension(self, extension: None) -> TimestampRequestBuilder:
raise NotImplemented("Adding extensions is not yet supported.")
def add_extension(self, _extension: None) -> TimestampRequestBuilder:
"""Add an extension."""
msg = "Adding extensions is not yet supported."
raise NotImplementedError(msg)

def hash_algorithm(self, hash_algorihtm: _AllowedHashTypes) -> TimestampRequestBuilder:
"""Set the Hash algorithm used."""
if hash_algorihtm not in HashAlgorithm:
msg = f"{hash_algorihtm} is not a supported hash."
raise TypeError(msg)

return TimestampRequestBuilder(
self._data, hash_algorihtm, self._req_policy, self._cert_req, self._extensions
)

def cert_request(self, *, cert_request: bool = False) -> TimestampRequestBuilder:
"""Set the cert request field."""
if not isinstance(cert_request, bool):
msg = "Cert request must be a boolean."
raise TypeError(msg)

return TimestampRequestBuilder(
self._data, self._algorithm, self._req_policy, cert_request, self._extensions
)

def request_policy(self, request_policy: int) -> TimestampRequestBuilder:
"""Set the request policy field."""
if not isinstance(request_policy, int):
msg = "Request policy must be an integer."
raise TypeError(msg)

return TimestampRequestBuilder(
self._data, self._algorithm, request_policy, self._cert_req, self._extensions
)

def build(self) -> _rust.TimeStampRequest:
"""Build a TimestampRequest."""
if self._data is None:
msg = "Data must be for a Timestamp Request."
raise ValueError(msg)

if self._algorithm is None:
self._algorithm = HashAlgorithm.SHA512

return _rust.create_timestamp_request(self._data)


def build(self):
raise NotImplemented("Building is not yet supported.")
def decode_timestamp_response(data: bytes) -> _rust.TimeStampResponse:
"""Decode a Timestamp response."""
return _rust.parse_timestamp_response(data)
Empty file.

0 comments on commit fe0d083

Please sign in to comment.