Basic structure in place

This commit is contained in:
Darryl Nixon 2023-06-06 15:51:54 -07:00
parent ffd4fe4012
commit 8edd610e7c
9 changed files with 201 additions and 1 deletions

0
crowdtls/__init__.py Normal file
View file

50
crowdtls/cli.py Normal file
View file

@ -0,0 +1,50 @@
from typing import Dict
from typing import List
from fastapi import FastAPI
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.future import select
from sqlmodel import SQLModel
from crowdtls.helpers import decode_der
from db import CertificateChain
DATABASE_URL = "postgresql+asyncpg://user:password@localhost:5432/database"
engine = create_async_engine(DATABASE_URL, echo=True)
app = FastAPI()
@app.on_event("startup")
async def startup_event():
async with engine.begin() as connection:
await connection.run_sync(SQLModel.metadata.create_all)
@app.post("/check")
async def check_fingerprints(fingerprints: Dict[str, List[int]]):
fps = fingerprints.get("fps")
async with AsyncSession(engine) as session:
for fp in fps:
stmt = select(CertificateChain).where(CertificateChain.fingerprint == fp)
result = await session.execute(stmt)
certificate = result.scalars().first()
if not certificate:
return {"send": True}
return {"send": False}
@app.post("/new")
async def new_fingerprints(fingerprints: Dict[str, List[int]]):
async with AsyncSession(engine) as session:
for fp, _ in fingerprints.items():
stmt = select(CertificateChain).where(CertificateChain.fingerprint == fp)
result = await session.execute(stmt)
certificate = result.scalars().first()
if not certificate:
new_certificate = decode_der(fp)
session.add(new_certificate)
pass
await session.commit()
return {"status": "OK"}

22
crowdtls/db.py Normal file
View file

@ -0,0 +1,22 @@
from sqlalchemy import Integer
from sqlalchemy import LargeBinary
from sqlalchemy.dialects.postgresql import JSONB
from sqlmodel import Field
from sqlmodel import SQLModel
class CertificateChain(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
fingerprint: str = Field(index=True)
domain_name: str
raw_der_certificate: LargeBinary
version: int
serial_number: str
signature: LargeBinary
issuer: JSONB
validity: JSONB
subject: JSONB
subject_public_key_info: JSONB
issuer_unique_id: Integer
subject_unique_id: Integer
extensions: JSONB

30
crowdtls/helpers.py Normal file
View file

@ -0,0 +1,30 @@
from typing import List
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from crowdtls.db import CertificateChain
def decode_der(raw_der_certificate: List[int]) -> CertificateChain:
# Convert list of integers to bytes
der_cert_bytes = bytes(raw_der_certificate)
# Parse the DER certificate
cert = x509.load_der_x509_certificate(der_cert_bytes, default_backend())
certificate_chain = CertificateChain(
raw_der_certificate=der_cert_bytes,
version=cert.version.value,
serial_number=cert.serial_number,
signature=cert.signature,
issuer=cert.issuer.rfc4514_string(),
validity={"not_valid_before": cert.not_valid_before, "not_valid_after": cert.not_valid_after},
subject=cert.subject.rfc4514_string(),
subject_public_key_info=cert.public_key().public_bytes(),
issuer_unique_id=cert.issuer_unique_id,
subject_unique_id=cert.subject_unique_id,
extensions=[str(ext) for ext in cert.extensions],
)
return certificate_chain