Skip to content

Commit

Permalink
Merge pull request #8 from amphineko/feat-sqlite-pki
Browse files Browse the repository at this point in the history
Use SQLite as storage backend for PKI
  • Loading branch information
amphineko authored Mar 9, 2024
2 parents e6febb4 + ebedb88 commit 81073c2
Show file tree
Hide file tree
Showing 42 changed files with 1,393 additions and 1,037 deletions.
6 changes: 3 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
"source=${localWorkspaceFolder}/data,target=/data,type=bind,consistency=cached"
],
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {},
"ghcr.io/devcontainers/features/git:1": {}
"ghcr.io/devcontainers/features/common-utils:2": {}
},
"customizations": {
"vscode": {
"extensions": [
"bierner.github-markdown-preview",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
"qwtel.sqlite-viewer"
],
"settings": {
"[typescript]": {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/api/mpsks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as t from "io-ts/lib/index"

import { MPSKType } from "../types/MPSK"
import { MPSKType } from "../types/mpsks/MPSK"

export const CreateOrUpdateMPSKRequestType = MPSKType

Expand Down
44 changes: 30 additions & 14 deletions packages/common/api/pki.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
import * as t from "io-ts"

import { RelativeDistinguishedNamesType } from "../types/RelativeDistinguishedNames"
import { SerialNumberStringType } from "../types/SerialNumberString"

export const CertificateSummaryType = t.type({
issuer: RelativeDistinguishedNamesType,
hexSerialNumber: SerialNumberStringType,
publicKey: t.string,
signature: t.string,
subject: RelativeDistinguishedNamesType,
validNotAfter: t.number,
validNotBefore: t.number,
})

export type CertificateSummary = t.TypeOf<typeof CertificateSummaryType>
import {
CertificateMetadata,
CertificateMetadataType,
EncodedCertificateMetadata,
} from "../types/pki/CertificateMetadata"
import { RelativeDistinguishedNames, RelativeDistinguishedNamesType } from "../types/pki/RelativeDistinguishedNames"

/**
* Extended metadata for user interface
*/
export interface CertificateSummary extends CertificateMetadata {
issuer: RelativeDistinguishedNames
publicKey: string
signature: string
}

interface EncodedCertificateSummary extends EncodedCertificateMetadata {
issuer: RelativeDistinguishedNames
publicKey: string
signature: string
}

export const CertificateSummaryType: t.Type<CertificateSummary, EncodedCertificateSummary> = t.intersection([
CertificateMetadataType,
t.type({
issuer: RelativeDistinguishedNamesType,
publicKey: t.string,
signature: t.string,
}),
])

export const GetPkiSummaryResponse = t.partial({
ca: CertificateSummaryType,
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as t from "io-ts/lib/index"

import { CallingStationId, CallingStationIdType } from "./CallingStationId"
import { Name, NameType } from "./Name"
import { PSK, PSKType } from "./PSK"
import { Name, NameType } from "../Name"

export interface CallingStationIdAuthentication {
callingStationId: CallingStationId
Expand Down
File renamed without changes.
33 changes: 33 additions & 0 deletions packages/common/types/pki/CertificateMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as t from "io-ts"

import { RelativeDistinguishedNames, RelativeDistinguishedNamesType } from "./RelativeDistinguishedNames"
import { SerialNumberString, SerialNumberStringType } from "./SerialNumberString"
import { DateFromUnixTimestamp } from "../Date"

/**
* Metadata extracted from a certificate
* For storage lookup without needing to parse the entire certificate.
*/
export interface CertificateMetadata {
readonly subject: RelativeDistinguishedNames
readonly serialNumber: SerialNumberString

readonly notBefore: Date
readonly notAfter: Date
}

export interface EncodedCertificateMetadata {
subject: RelativeDistinguishedNames
serialNumber: string

notBefore: number
notAfter: number
}

export const CertificateMetadataType: t.Type<CertificateMetadata, EncodedCertificateMetadata> = t.type({
subject: RelativeDistinguishedNamesType,
serialNumber: SerialNumberStringType,

notBefore: DateFromUnixTimestamp,
notAfter: DateFromUnixTimestamp,
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as t from "io-ts"

import { NonEmptyStringType } from "./StringWithLengthRange"
import { NonEmptyStringType } from "../StringWithLengthRange"

export const RelativeDistinguishedNamesType = t.type({
commonName: NonEmptyStringType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@ export const SerialNumberStringType = new t.Type<string, string, unknown>(
(u, c) =>
F.pipe(
t.string.validate(u, c),
E.map((u) => u.split(":").map((s) => s.trim().toLowerCase())),
E.flatMap((u) =>
u.length > 0 && u.length <= 20 && u.every((s) => /^[0-9a-f]{2}$/.test(s))
? t.success(u.join(":"))
: t.failure(u, c, "Input is not a valid serial number"),
E.map((s) => s.toLowerCase().replace(/:/g, "")),
E.tap(
F.flow(
E.fromPredicate(
(s) => /^[0-9a-f]+$/.test(s),
() => "Serial number contains non-hexadecimal characters",
),
E.filterOrElse(
(s) => s.length === 32,
() => "Serial number is not 16 bytes long",
),
E.orElse((e) => t.failure(u, c, e)),
),
),
),
(a) => a,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
export type KeyGenParams = EcKeyGenParams | RsaHashedKeyGenParams

export type HashAlgorithm = "SHA-256" | "SHA-384" | "SHA-512"

export interface PkiMode {
certHashAlg: HashAlgorithm
key: KeyGenParams
key: EcKeyGenParams | RsaHashedKeyGenParams
}
6 changes: 6 additions & 0 deletions packages/common/utils/TaskEither.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ export function getOrThrow(): <A, E extends Error = Error>(TE: TE.TaskEither<E,
throw e
})
}

export function filterNullish<E2, A>(
onNullish: () => E2,
): <E1>(ma: TE.TaskEither<E1, A>) => TE.TaskEither<E1 | E2, NonNullable<A>> {
return TE.flatMap((a) => (a ? TE.right(a) : TE.left(onNullish())))
}
Loading

0 comments on commit 81073c2

Please sign in to comment.