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

Merge release 3.4.2 from pilot branch to master branch #230

Merged
merged 53 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
486dcbc
Clarification about password protected zip files
whartond Nov 14, 2019
77db63a
include Suricata-Update in list of ruleset management tools
whartond Nov 14, 2019
9c200d2
include Suricata-Update link in list of ruleset management tools
whartond Nov 14, 2019
094e725
README tweak
whartond Nov 14, 2019
4e848b8
use specific flowsynth files instead of latest from repo
Dec 30, 2019
207822a
Merge branch 'master' into pilot
whartond Nov 3, 2023
05db72d
Merge pull request #169 from whartond/pilot
rkoumis Aug 12, 2024
d8d8ed7
Merge pull request #186 from secureworks/master
rkoumis Nov 10, 2024
d254191
Merge pull request #188 from secureworks/master
rkoumis Nov 10, 2024
f0131b3
Use pyproject.toml (#184)
rkoumis Nov 10, 2024
508e04c
Merge pull request #189 from rkoumis/184-pyproject-toml
rkoumis Nov 10, 2024
fce3ec1
Ran "ruff format" changing single quotes to double
rkoumis Nov 10, 2024
584eb24
Merge pull request #190 from rkoumis/183-ruff-format
rkoumis Nov 10, 2024
668dda0
Ran ruff check --unsafe-fixes --fix
rkoumis Nov 10, 2024
70c5db3
Manual tweaks after running `ruff check --fix`
rkoumis Nov 10, 2024
bacab6a
Merge pull request #192 from rkoumis/183-ruff-check
rkoumis Nov 10, 2024
50247d3
Added github CI workflow
rkoumis Nov 10, 2024
f3173d6
Merge pull request #193 from rkoumis/191-github-actions
rkoumis Nov 11, 2024
081115c
Run unit tests #182
rkoumis Nov 11, 2024
edcdeb5
Automated lint fixes
rkoumis Nov 11, 2024
d780e3d
Merge pull request #194 from rkoumis/182-unit-tests-can-run
rkoumis Nov 11, 2024
a68d7f9
Run ruff format and check on dalton agent
rkoumis Nov 11, 2024
8434d75
Manual fixes or tweaks to make ruff happy
rkoumis Nov 11, 2024
a324062
Merge pull request #195 from rkoumis/183-lint-dalton-agent
rkoumis Nov 11, 2024
7c031ae
Updated nginx to 1.27.2
rkoumis Nov 11, 2024
6587cc8
Merge pull request #202 from rkoumis/200-update-nginx
rkoumis Nov 11, 2024
8eb3004
Update redis from 3.2 to 7.4
rkoumis Nov 11, 2024
c616462
Merge pull request #205 from rkoumis/201-update-redis
rkoumis Nov 11, 2024
dd97d59
Add unit tests for the flowsynth web UI
rkoumis Nov 12, 2024
55dc3dd
Merge pull request #206 from rkoumis/204-flowsynth-tests
rkoumis Nov 12, 2024
50e8bf0
Sort imports using ruff
rkoumis Nov 12, 2024
4c3f4ac
Merge pull request #208 from rkoumis/207-run-isort
rkoumis Nov 12, 2024
eab3764
Additional code checking by ruff
rkoumis Nov 12, 2024
7dc5a02
Merge pull request #210 from rkoumis/209-ruff-bugbears
rkoumis Nov 12, 2024
9ede867
Use pre-built zeek images
rkoumis Nov 12, 2024
dc2d1e3
Merge pull request #211 from rkoumis/181-pre-built-zeek
rkoumis Nov 12, 2024
a4d784d
Use bump-my-version tool to help manage versioning
rkoumis Nov 12, 2024
1612c82
Bump version: 3.3.6 → 3.4.0
rkoumis Nov 12, 2024
42452d6
Bump dalton-agent version: 3.1.1 → 3.1.2
rkoumis Nov 12, 2024
adf82a1
A couple of issues that the linter did not like
rkoumis Nov 12, 2024
a259d7e
Merge pull request #212 from rkoumis/197-bump-version
rkoumis Nov 12, 2024
5173193
redis is not happy with a boolean
rkoumis Nov 13, 2024
20d476b
Merge pull request #214 from rkoumis/203-zeek-json-bug
rkoumis Nov 13, 2024
b22d394
Fix for issue #213 where zeek logs were not shown
rkoumis Nov 14, 2024
52e86f4
Merge pull request #216 from rkoumis/213-zeek-results-borked
rkoumis Nov 14, 2024
57587a8
Add unit tests for dalton app
rkoumis Nov 13, 2024
6fc6135
Merge pull request #215 from rkoumis/203-dalton-unit-tests
rkoumis Nov 14, 2024
5d162dc
Bump version: 3.4.0 → 3.4.1
rkoumis Nov 14, 2024
b1101d3
Merge pull request #217 from rkoumis/bump-version-to-3-4-1
rkoumis Nov 14, 2024
02f3630
Update flask dependencies
rkoumis Nov 15, 2024
6680037
Allow the user or the agent to upload large files
rkoumis Nov 15, 2024
bec6082
Bump version: 3.4.1 → 3.4.2
rkoumis Nov 15, 2024
ab4e0ea
Merge pull request #222 from rkoumis/180-flask-dependency-update
rkoumis Nov 15, 2024
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
52 changes: 52 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: Python application

on:
push:
branches: [ "master", "pilot" ]
pull_request:
branches: [ "master", "pilot" ]

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
make venv
- name: Run the lint checker
run: |
make lint

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
make venv
- name: Run the tests
run: |
make test

docker-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run the hadolint tool on the Dockerfile files
run: |
make hadolint
32 changes: 32 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,35 @@ Zeek Enhancements (#177)

Author: Nikhileswar Reddy <nreddy@octolabs.io>

3.4.0 (2024-11-12)
##################

Version 3.4.x is available initially on the pilot branch,
in a sort of pre-release mode.

* Use pyproject.toml (#184) (#189)
* Use ruff format to format the code (#183) (#190)
* Use ruff check --fix to make style changes (#183) (#192)
* Add github actions CI (#191) (#193)
* Be able to run unit tests on dalton and flowsynth (#182) (#194)
* Update nginx from 1.19 to 1.27 (#200) (#202)
* Update redis from 3.2 to 7.4 (#201)
* Add unit tests for flowsynth (#204)
* Use ruff to sort and format imports (#207)
* Use ruff to detect flake8 bugbears (B) (#209)
* Use pre-built zeek images (#181)
* Use bump-my-version to update the version and tag (#197)
* Also, use bump-my-version to update the dalton-agent version
* Also, show the dalton controller version on the About page

3.4.1 (2024-11-14)
##################

* Fixed bug with zeek processing. (#213) (#214) (#216)
* Added some unit tests. (#203) (#215)

3.4.2 (2024-11-15)
##################

* Updated flask dependencies (#180) (#222)
* Configure flask maximum content length
24 changes: 16 additions & 8 deletions Dockerfile-dalton
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
FROM python:3.9.0
MAINTAINER David Wharton
FROM python:3.10.15

# wireshark needed for mergecap; statically compiled
# mergecap would be smaller but doing this for now
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get -y install wireshark-common \
p7zip-full

# hadolint ignore=DL3008
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
wireshark-common \
p7zip-full \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# for development; not needed by the app
#RUN apt-get install -y less nano net-tools

WORKDIR /opt/dalton

COPY requirements.txt /opt/dalton/requirements.txt
RUN pip install -r requirements.txt

COPY pyproject.toml /opt/dalton
COPY app /opt/dalton/app
RUN pip install --no-cache-dir -e .
COPY run.py /opt/dalton/run.py
COPY dalton.conf /opt/dalton/dalton.conf
COPY rulesets /opt/dalton/rulesets
COPY engine-configs /opt/dalton/engine-configs

CMD python /opt/dalton/run.py -c /opt/dalton/dalton.conf
STOPSIGNAL SIGINT
EXPOSE 8080

# Note: if changing the next line, also look to change the command in docker-compose.yml
CMD ["flask", "--app", "app", "run", "--port=8080", "--host=0.0.0.0"]
10 changes: 4 additions & 6 deletions Dockerfile-nginx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# spin up nginx with custom conf
FROM nginx:1.19.4
MAINTAINER David Wharton
FROM nginx:1.27.2

ARG DALTON_EXTERNAL_PORT
ARG DALTON_EXTERNAL_PORT_SSL
ARG DALTON_EXTERNAL_PORT=80
ARG DALTON_EXTERNAL_PORT_SSL=443

RUN rm /etc/nginx/nginx.conf && rm -rf /etc/nginx/conf.d
COPY nginx-conf/nginx.conf /etc/nginx/nginx.conf
Expand All @@ -13,6 +12,5 @@ COPY nginx-conf/tls /etc/nginx/tls
# adjust nginx config so redirects point to external port(s).
# order of sed operations matters since one replaced string is a subset of the other.
RUN sed -i 's/REPLACE_AT_DOCKER_BUILD_SSL/'"${DALTON_EXTERNAL_PORT_SSL}"'/' /etc/nginx/conf.d/dalton.conf
# hadolint ignore=DL3059
RUN sed -i 's/REPLACE_AT_DOCKER_BUILD/'"${DALTON_EXTERNAL_PORT}"'/' /etc/nginx/conf.d/dalton.conf

CMD nginx
39 changes: 39 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

VENV := $(or ${VENV},${VENV},$(CURDIR)/.venv)
PIP=$(VENV)/bin/pip
PYTHON=$(VENV)/bin/python
PYTEST=$(VENV)/bin/pytest
COVERAGE=$(VENV)/bin/coverage
RUFF=$(VENV)/bin/ruff
ACTIVATE=$(VENV)/bin/activate
BUMPVERSION=$(VENV)/bin/bump-my-version
BUMPPART ?= patch

venv $(VENV):
python3 -m venv $(VENV)
$(PIP) install --upgrade pip wheel
$(PIP) install -e . -e ".[testing]" -e ".[devtools]"

test: $(VENV)
. $(ACTIVATE) && $(PYTEST) tests

coverage: $(VENV)
. $(ACTIVATE) && $(COVERAGE) run -m pytest tests
$(COVERAGE) report

lint: $(VENV)
$(RUFF) format --check
$(RUFF) check

fix: $(VENV)
$(RUFF) format
$(RUFF) check --fix

hadolint: Dockerfile-dalton Dockerfile-nginx dalton-agent/Dockerfiles/Dockerfile_*
docker run -t --rm -v `pwd`:/app -w /app hadolint/hadolint /bin/hadolint $^

bumpversion: $(VENV) pyproject.toml
$(BUMPVERSION) bump $(BUMPPART)

bumpagent: $(VENV) pyproject.toml
$(BUMPVERSION) bump --config-file dalton-agent/.bumpversion.toml $(BUMPPART)
9 changes: 5 additions & 4 deletions api/dalton.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Dalton API client."""
import requests

import time

import requests
from requests.exceptions import HTTPError


RETRIES = 3
SLEEP_TIME = 60

Expand Down Expand Up @@ -142,6 +142,7 @@ def get_current_sensors(self) -> dict:
'tech': 'suricata/5.0.7',
'agent_version': '3.1.1'}}
"""
response = self._dalton_get("dalton/controller_api/get-current-sensors-json-full")
response = self._dalton_get(
"dalton/controller_api/get-current-sensors-json-full"
)
return response.json()

1 change: 1 addition & 0 deletions api/examples/job_submission.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Example on how to submit a job using the Dalton Client API. Mock data is in mocks directory."""

import os

from api.dalton import DaltonAPI
Expand Down
50 changes: 50 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import logging
import os

from flask import Flask

from app.dalton import dalton_blueprint, ensure_rulesets_exist, setup_dalton_logging
from app.flowsynth import flowsynth_blueprint, setup_flowsynth_logging

__version__ = "3.4.2"


def create_app(test_config=None):
"""Create the flask app."""
curdir = os.path.dirname(os.path.abspath(__file__))
static_folder = os.path.join(curdir, "static")
daltonfs = Flask("app", static_folder=static_folder)
if test_config:
# load the test config if passed in
daltonfs.config.from_mapping(test_config)

if not daltonfs.testing:
setup_dalton_logging()
setup_flowsynth_logging()
ensure_rulesets_exist()

# register modules
#
# dalton
daltonfs.register_blueprint(dalton_blueprint)

# flowsynth
daltonfs.register_blueprint(flowsynth_blueprint, url_prefix="/flowsynth")

daltonfs.debug = True

# Apparently the werkzeug default logger logs every HTTP request
# which bubbles up to the root logger and gets output to the
# console which ends up in the docker logs. Since each agent
# checks in every second (by default), this can be voluminous
# and is superfluous for my current needs.
try:
logging.getLogger("werkzeug").setLevel(logging.ERROR)
except Exception:
pass

# Allow the user or the agent to upload large files
daltonfs.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 1024
daltonfs.config["MAX_FORM_MEMORY_SIZE"] = None

return daltonfs
66 changes: 35 additions & 31 deletions app/certsynth.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import struct
import binascii
import re
import struct

SYNTH_START = '''
SYNTH_START = """
## Client Hello
default > (
content:"\\x80\\x80"; #Length
Expand All @@ -16,15 +16,15 @@
## Server Hello and Certificate
default < (
### Server Hello
content:"\\x16\\x03\\x01\\x00Q\\x02\\x00\\x00M\\x03\\x01U\\xe8\\x83\\x0f\\xa1\\xe8\\xcd\\xc6^k\\xae`\\xf4\\xbe\\x0er\\xab~w,\\xce\\xf6L\\x89#\\xc9\\xbaU\\x8b\\xae\\x0ef\\x20\\xcf\\xb4\\xc1\\xb9\\xb0-\\x1e\\xe6Zl\\x0f\\xff\\xfd\\xe3)\\x97\\x89cy\\xa9\\xdbNV\\x83\\xa5\\x97:\\x12Td\\x09\\xac\\x009\\x00\\x00\\x05\\xff\\x01\\x00\\x01\\x00";'''
content:"\\x16\\x03\\x01\\x00Q\\x02\\x00\\x00M\\x03\\x01U\\xe8\\x83\\x0f\\xa1\\xe8\\xcd\\xc6^k\\xae`\\xf4\\xbe\\x0er\\xab~w,\\xce\\xf6L\\x89#\\xc9\\xbaU\\x8b\\xae\\x0ef\\x20\\xcf\\xb4\\xc1\\xb9\\xb0-\\x1e\\xe6Zl\\x0f\\xff\\xfd\\xe3)\\x97\\x89cy\\xa9\\xdbNV\\x83\\xa5\\x97:\\x12Td\\x09\\xac\\x009\\x00\\x00\\x05\\xff\\x01\\x00\\x01\\x00";"""

SYNTH_END = '''
SYNTH_END = """
### Server Key Exchange
content:"\\x16\\x03\\x01\\x01\\x8d\\x0c\\x00\\x01\\x89\\x00\\x80\\xbb\\xbc-\\xca\\xd8Ft\\x90|C\\xfc\\xf5\\x80\\xe9\\xcf\\xdb\\xd9X\\xa3\\xf5h\\xb4-K\\x08\\xee\\xd4\\xeb\\x0f\\xb3PLl\\x03\\x02v\\xe7\\x10\\x80\\x0c\\\\xcb\\xba\\xa8\\x92&\\x14\\xc5\\xbe\\xec\\xa5e\\xa5\\xfd\\xf1\\xd2\\x87\\xa2\\xbc\\x04\\x9b\\xe6w\\x80`\\xe9\\x1a\\x92\\xa7W\\xe3\\x04\\x8fh\\xb0v\\xf7\\xd3l\\xc8\\xf2\\x9b\\xa5\\xdf\\x81\\xdc,\\xa7%\\xec\\xe6bp\\xcc\\x9aP5\\xd8\\xce\\xce\\xef\\x9e\\xa0'Jc\\xab\\x1eX\\xfa\\xfdI\\x88\\xd0\\xf6]\\x14gW\\xda\\x07\\x1d\\xf0E\\xcf\\xe1k\\x9b\\x00\\x01\\x02\\x00\\x80\\xa9\\xc5y)\\U\\x00\\x1f\\xa30\\x9b\\x8e\\xd6.\\xed\\x01\\xe9VY0\\x9e\\x03\\x95\\x1b\\x88[q\\xdd\\xfd\\x16\\x0e\\x1a\\xc3\\xbd\\xd3\\x1c\\xbc\\x92\\xa1o\\xed\\xa5T\\xea\\xaa\\xf7\\xdd\\xcd\\xd7\\xb8\\x20E\\x9b\\x1a\\xd4H}[\\xf46\\x98dL\\x0d\\xb6<A\\x98[\\x8c\\x95\\xc5\\\\x0a\\xef>\\xfc\\xb2\\x0d\\xf7\\x94\\xecv\\xd5\\x1f\\xf2\\x85;\\xa6\\xf6\\xf2U\\xcb\\x16\\xc4z\\xa1/\\xdeq\\xf3\\xb0\\x20\\x19\\xef\\xc8\\xc9\\xa5\\x15\\xae\\x9f\\xe9\\x07:\\x0d\\x10\\xbe\\xc8\\xb3\\x98Zh\\xe6k\\x7f5\\x1d\\x8f\\x00\\x80\\x19\\xbb\\x17\\xd6e\\x00\\xc8Y\\x95L\\xde\\xdb\\x9b\\xc7I\\x20F\\x96Po\\xf8\\xedV\\x92\\x85\\xe5V\\xf2zC\\x06\\xcb\\xcc\\xfe(\\x82\\x1c\\x11\\x9d\\xb8\\xd3wT\\x9c\\x08\\xe6\\x0aA\\x06\\xbax\\xb8\\x85\\x94p+\\x88/\\xb4\\x20%\\x1bhx\\xc462\\xa4;\\x9e\\xe7\\x98`\\x01]<q)!\\x9c\\xe7\\x8a6\\xd4\\xd9\\xb6\\x0f\\xbc*\\x0aV\\xf6\\x1cp\\xb7\\xf6[P\\x85\\xfc\\x9f.\\xc3\\x14k\\x0c\\x80\\xf7\\x20\\xf3\\xf4\\xac}\\x14\\xe66lz\\xf5\\xe9Yf\\x07\\x1a\\x00f\\x98\\x90";
### Server Hello Done
content:"\\x16\\x03\\x01\\x00\\x04\\x0e\\x00\\x00\\x00"; );'''
content:"\\x16\\x03\\x01\\x00\\x04\\x0e\\x00\\x00\\x00"; );"""

SYNTH_CERTIFICATES = '''
SYNTH_CERTIFICATES = """
### Certificates Handshake
content:"\\x16"; # Type Handshake
content:"\\x03\\x01"; # Version (TLS 1.0)
Expand All @@ -34,20 +34,20 @@
content:"{1}"; # Certificate Handshake length: Certificate length + 6 (3 bytes)
content:"{2}"; # Certificates length: Certificate length + 3 (3 bytes)
content:"{3}"; # Certificate Length (3 bytes)
content:"{4}"; # DER certificate bytes'''
content:"{4}"; # DER certificate bytes"""


def pem_cert_validate(pem_str):
"""Validate a Certificate PEM string
Returns
True if valid form False otherwise
Returns
True if valid form False otherwise
"""
lines = pem_str.splitlines()
if lines[0] != '-----BEGIN CERTIFICATE-----':
if lines[0] != "-----BEGIN CERTIFICATE-----":
return False
elif lines[-1] != '-----END CERTIFICATE-----':
elif lines[-1] != "-----END CERTIFICATE-----":
return False
if not re.match(r'[a-zA-Z0-9+/]={0,2}', "".join(lines[1:-1])):
if not re.match(r"[a-zA-Z0-9+/]={0,2}", "".join(lines[1:-1])):
return False
else:
return True
Expand All @@ -56,43 +56,47 @@ def pem_cert_validate(pem_str):
def pem_to_der(pem_str):
"""Convert a PEM string to DER format"""
lines = pem_str.strip().splitlines()
der = binascii.a2b_base64(''.join(lines[1:-1]))
der = binascii.a2b_base64("".join(lines[1:-1]))
return der


def to_synth_bytes(some_str):
"""Convert a string to flowsynth formatted hex"""
str_hex = binascii.hexlify(some_str).decode("utf-8")
out = "\\x" + "\\x".join(
[str_hex[i:i + 2] for i in range(0, len(str_hex), 2)])
out = "\\x" + "\\x".join([str_hex[i : i + 2] for i in range(0, len(str_hex), 2)])
return out


def cert_to_synth(cert_str, format):
"""Generates flowsynth of a TLS handshake for the given certificate
cert_str -- A string of a PEM or DER encoded certificate
format -- "PEM or "DER"
cert_str -- A string of a PEM or DER encoded certificate
format -- "PEM or "DER"
"""

cert_bytes = ""
if format == 'PEM':
if format == "PEM":
# validate?
cert_bytes = pem_to_der(cert_str)
elif format == 'DER':
elif format == "DER":
cert_bytes = cert_str
handshake_len_bytes = struct.pack('>H', len(cert_bytes) + 10)
handshake_len_bytes = struct.pack(">H", len(cert_bytes) + 10)
handshake_len_synth_bytes = to_synth_bytes(handshake_len_bytes)
cert_handshake_len_bytes = struct.pack('>I', len(cert_bytes) + 6)[1:]
cert_handshake_len_bytes = struct.pack(">I", len(cert_bytes) + 6)[1:]
cert_handshake_len_synth_bytes = to_synth_bytes(cert_handshake_len_bytes)
certs_len_bytes = struct.pack('>I', len(cert_bytes) + 3)[1:]
certs_len_bytes = struct.pack(">I", len(cert_bytes) + 3)[1:]
certs_len_synth_bytes = to_synth_bytes(certs_len_bytes)
cert_len_bytes = struct.pack('>I', len(cert_bytes))[1:]
cert_len_bytes = struct.pack(">I", len(cert_bytes))[1:]
cert_len_synth_bytes = to_synth_bytes(cert_len_bytes)
return "".join([SYNTH_START,
SYNTH_CERTIFICATES.format(
handshake_len_synth_bytes,
cert_handshake_len_synth_bytes,
certs_len_synth_bytes,
cert_len_synth_bytes,
to_synth_bytes(cert_bytes)),
SYNTH_END])
return "".join(
[
SYNTH_START,
SYNTH_CERTIFICATES.format(
handshake_len_synth_bytes,
cert_handshake_len_synth_bytes,
certs_len_synth_bytes,
cert_len_synth_bytes,
to_synth_bytes(cert_bytes),
),
SYNTH_END,
]
)
Loading
Loading