Skip to content

Commit 4483435

Browse files
committed
Make library a bit more generic
1 parent 3cea575 commit 4483435

File tree

8 files changed

+186
-154
lines changed

8 files changed

+186
-154
lines changed

CLAUDE.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,19 @@ The system implements a hierarchical certificate authority model using flags (`s
4545
- `ROOT_CA` (0x0001): Self-signed root certificate authorities
4646
- `INTERMEDIATE_CA` (0x0002): Enables signing of CA-level certificates when combined with `CA`
4747
- `CA` (0x0004): Required to sign any certificate; alone it can sign only end-entity (non-CA) certificates
48-
- `DOCUMENT_SIGNER` (0x0100): Can sign documents
49-
- `TEMPLATE_SIGNER` (0x0200): Can sign templates
48+
- `END_ENTITY_FLAG_1` (0x0100): Generic end-entity capability 1
49+
- `END_ENTITY_FLAG_2` (0x0200): Generic end-entity capability 2
50+
- `END_ENTITY_FLAG_3` (0x0400): Generic end-entity capability 3
51+
- `END_ENTITY_FLAG_4` (0x0800): Generic end-entity capability 4
52+
- `END_ENTITY_FLAG_5` (0x1000): Generic end-entity capability 5
53+
- `END_ENTITY_FLAG_6` (0x2000): Generic end-entity capability 6
54+
- `END_ENTITY_FLAG_7` (0x4000): Generic end-entity capability 7
55+
- `END_ENTITY_FLAG_8` (0x8000): Generic end-entity capability 8
5056

5157
**Key Validation Rules:**
5258
- Signers must have `CA` to issue any certificates
5359
- Signing a certificate with CA-level flags additionally requires `INTERMEDIATE_CA`
54-
- End-entity flags (`DOCUMENT_SIGNER`, `TEMPLATE_SIGNER`) must be a subset of the signer's flags
60+
- End-entity flags (END_ENTITY_FLAG_1 through END_ENTITY_FLAG_8) must be a subset of the signer's flags
5561
- `ROOT_CA` certificates must be self-signed
5662

5763
### Directory Structure

SPECIFICATION.md

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,14 @@ The following structure applies to `AlgVer = 0x01` (Ed25519 v1 — fixed sizes,
4444
- `0x0001`**Root CA**
4545
- `0x0002`**Intermediate CA**
4646
- `0x0004`**CA**
47-
- `0x0100`**Document Signer**
48-
- `0x0200`**Template Signer**
47+
- `0x0100`**End Entity Flag 1**
48+
- `0x0200`**End Entity Flag 2**
49+
- `0x0400`**End Entity Flag 3**
50+
- `0x0800`**End Entity Flag 4**
51+
- `0x1000`**End Entity Flag 5**
52+
- `0x2000`**End Entity Flag 6**
53+
- `0x4000`**End Entity Flag 7**
54+
- `0x8000`**End Entity Flag 8**
4955
- Other bits **reserved** (must be `0` on encode; ignore on decode).
5056
- Implementations **must not** modify the `Flags` field when re‑emitting a certificate. Any reserved bits present in input data
5157
**must be preserved** exactly to avoid altering signed bytes.
@@ -75,7 +81,7 @@ The following structure applies to `AlgVer = 0x01` (Ed25519 v1 — fixed sizes,
7581
- Cannot sign any certificates.
7682

7783
### End‑entity flags (non‑CA) inheritance
78-
- End‑entity flags are the non‑CA bits (e.g., `DOCUMENT_SIGNER (0x0100)`, `TEMPLATE_SIGNER (0x0200)`).
84+
- End‑entity flags are the non‑CA bits (e.g., flags 0x0100 through 0x8000).
7985
- A subject’s end‑entity flags must be a subset of its issuer’s end‑entity flags:
8086
- `Subject.EndEntityFlags ⊆ Issuer.EndEntityFlags`.
8187

@@ -100,14 +106,14 @@ Notes:
100106
### End‑Entity Inheritance Matrix
101107
Only illustrates the subset rule for end‑entity flags. CA‑level signing capability (issuer must have `CA` for non‑CA subjects, `INTERMEDIATE_CA` for CA‑level subjects) still applies separately.
102108

103-
Legend: Document = `0x0100`, Template = `0x0200`.
109+
Legend: Flag1 = `0x0100`, Flag2 = `0x0200`, etc.
104110

105-
| Issuer end‑entity flags | Subject: None | Subject: Document | Subject: Template | Subject: Document+Template |
106-
|------------------------:|:-------------:|:-----------------:|:-----------------:|:-------------------------:|
107-
| None || | | |
108-
| Document || | | |
109-
| Template || | | |
110-
| Document+Template || | | |
111+
| Issuer end‑entity flags | Subject: None | Subject: Flag1 | Subject: Flag2 | Subject: Flag1+Flag2 |
112+
|------------------------:|:-------------:|:--------------:|:--------------:|:--------------------:|
113+
| None |||||
114+
| Flag1 |||||
115+
| Flag2 |||||
116+
| Flag1+Flag2 |||||
111117

112118
Reminder: This matrix validates only the end‑entity subset requirement. The issuer must still have the appropriate CA‑level flag to sign the subject at all (see the Signing rules matrix above).
113119

@@ -126,7 +132,7 @@ Notes
126132
5. For each child/parent pair (issuer = parent):
127133
- For non-CA children: Issuer must have `CA`.
128134
- For CA-level children (has any of `ROOT_CA`, `INTERMEDIATE_CA`, `CA`): issuer must have `INTERMEDIATE_CA`.
129-
- End‑entity inheritance: For each end‑entity bit (`0x0100`, `0x0200`), if child has it, issuer must also have it (`Child.EndEntity ⊆ Issuer.EndEntity`).
135+
- End‑entity inheritance: For each end‑entity bit (0x0100 through 0x8000), if child has it, issuer must also have it (`Child.EndEntity ⊆ Issuer.EndEntity`).
130136
6. A certificate with `ROOT_CA` must be self‑signed and present in the trust store.
131137

132138
---

examples.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
CertificateFlag::ROOT_CA,
4444
CertificateFlag::CA,
4545
CertificateFlag::INTERMEDIATE_CA,
46-
CertificateFlag::DOCUMENT_SIGNER,
47-
CertificateFlag::TEMPLATE_SIGNER
46+
CertificateFlag::END_ENTITY_FLAG_1,
47+
CertificateFlag::END_ENTITY_FLAG_2
4848
]),
4949
signatures: []
5050
);
@@ -60,7 +60,7 @@
6060
CertificateFlag::ROOT_CA,
6161
CertificateFlag::CA,
6262
CertificateFlag::INTERMEDIATE_CA,
63-
CertificateFlag::DOCUMENT_SIGNER,
63+
CertificateFlag::END_ENTITY_FLAG_1,
6464
]),
6565
signatures: []
6666
);
@@ -74,8 +74,8 @@
7474
],
7575
flags: CertificateFlagsCollection::fromList([
7676
CertificateFlag::INTERMEDIATE_CA,
77-
CertificateFlag::DOCUMENT_SIGNER,
78-
CertificateFlag::TEMPLATE_SIGNER
77+
CertificateFlag::END_ENTITY_FLAG_1,
78+
CertificateFlag::END_ENTITY_FLAG_2
7979
]),
8080
signatures: []
8181
);
@@ -89,8 +89,8 @@
8989
],
9090
flags: CertificateFlagsCollection::fromList([
9191
CertificateFlag::INTERMEDIATE_CA,
92-
CertificateFlag::DOCUMENT_SIGNER,
93-
CertificateFlag::TEMPLATE_SIGNER
92+
CertificateFlag::END_ENTITY_FLAG_1,
93+
CertificateFlag::END_ENTITY_FLAG_2
9494
]),
9595
signatures: []
9696
);
@@ -104,8 +104,8 @@
104104
],
105105
flags: CertificateFlagsCollection::fromList([
106106
CertificateFlag::INTERMEDIATE_CA,
107-
CertificateFlag::DOCUMENT_SIGNER,
108-
CertificateFlag::TEMPLATE_SIGNER
107+
CertificateFlag::END_ENTITY_FLAG_1,
108+
CertificateFlag::END_ENTITY_FLAG_2
109109
]),
110110
signatures: []
111111
);
@@ -119,8 +119,8 @@
119119
],
120120
flags: CertificateFlagsCollection::fromList([
121121
CertificateFlag::INTERMEDIATE_CA,
122-
CertificateFlag::DOCUMENT_SIGNER,
123-
CertificateFlag::TEMPLATE_SIGNER
122+
CertificateFlag::END_ENTITY_FLAG_1,
123+
CertificateFlag::END_ENTITY_FLAG_2
124124
]),
125125
signatures: []
126126
);
@@ -134,8 +134,8 @@
134134
],
135135
flags: CertificateFlagsCollection::fromList([
136136
CertificateFlag::CA,
137-
CertificateFlag::DOCUMENT_SIGNER,
138-
CertificateFlag::TEMPLATE_SIGNER
137+
CertificateFlag::END_ENTITY_FLAG_1,
138+
CertificateFlag::END_ENTITY_FLAG_2
139139
]),
140140
signatures: []
141141
);
@@ -149,8 +149,8 @@
149149
],
150150
flags: CertificateFlagsCollection::fromList([
151151
CertificateFlag::INTERMEDIATE_CA,
152-
CertificateFlag::DOCUMENT_SIGNER,
153-
CertificateFlag::TEMPLATE_SIGNER
152+
CertificateFlag::END_ENTITY_FLAG_1,
153+
CertificateFlag::END_ENTITY_FLAG_2
154154
]),
155155
signatures: []
156156
);

src/DTO/CertificateFlag.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,29 @@ enum CertificateFlag: int
77
case ROOT_CA = 0x0001;
88
case INTERMEDIATE_CA = 0x0002;
99
case CA = 0x0004;
10-
case DOCUMENT_SIGNER = 0x0100;
11-
case TEMPLATE_SIGNER = 0x0200;
10+
case END_ENTITY_FLAG_1 = 0x0100;
11+
case END_ENTITY_FLAG_2 = 0x0200;
12+
case END_ENTITY_FLAG_3 = 0x0400;
13+
case END_ENTITY_FLAG_4 = 0x0800;
14+
case END_ENTITY_FLAG_5 = 0x1000;
15+
case END_ENTITY_FLAG_6 = 0x2000;
16+
case END_ENTITY_FLAG_7 = 0x4000;
17+
case END_ENTITY_FLAG_8 = 0x8000;
1218

1319
public function toString(): string
1420
{
1521
return match ($this) {
1622
self::ROOT_CA => 'Root CA',
1723
self::INTERMEDIATE_CA => 'Intermediate CA',
1824
self::CA => 'CA',
19-
self::DOCUMENT_SIGNER => 'Document Signer',
20-
self::TEMPLATE_SIGNER => 'Template Signer',
25+
self::END_ENTITY_FLAG_1 => 'End Entity Flag 1',
26+
self::END_ENTITY_FLAG_2 => 'End Entity Flag 2',
27+
self::END_ENTITY_FLAG_3 => 'End Entity Flag 3',
28+
self::END_ENTITY_FLAG_4 => 'End Entity Flag 4',
29+
self::END_ENTITY_FLAG_5 => 'End Entity Flag 5',
30+
self::END_ENTITY_FLAG_6 => 'End Entity Flag 6',
31+
self::END_ENTITY_FLAG_7 => 'End Entity Flag 7',
32+
self::END_ENTITY_FLAG_8 => 'End Entity Flag 8',
2133
};
2234
}
2335

src/DTO/CertificateFlagsCollection.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ private function __construct(public readonly int $value)
2525
public static function EndEntityFlags(): self
2626
{
2727
return self::fromList([
28-
CertificateFlag::DOCUMENT_SIGNER,
29-
CertificateFlag::TEMPLATE_SIGNER,
28+
CertificateFlag::END_ENTITY_FLAG_1,
29+
CertificateFlag::END_ENTITY_FLAG_2,
30+
CertificateFlag::END_ENTITY_FLAG_3,
31+
CertificateFlag::END_ENTITY_FLAG_4,
32+
CertificateFlag::END_ENTITY_FLAG_5,
33+
CertificateFlag::END_ENTITY_FLAG_6,
34+
CertificateFlag::END_ENTITY_FLAG_7,
35+
CertificateFlag::END_ENTITY_FLAG_8,
3036
]);
3137
}
3238

@@ -77,16 +83,6 @@ public function hasCA(): bool
7783
return $this->has(CertificateFlag::CA);
7884
}
7985

80-
public function hasDocumentSigner(): bool
81-
{
82-
return $this->has(CertificateFlag::DOCUMENT_SIGNER);
83-
}
84-
85-
public function hasTemplateSigner(): bool
86-
{
87-
return $this->has(CertificateFlag::TEMPLATE_SIGNER);
88-
}
89-
9086
public function isCA(): bool
9187
{
9288
return $this->hasRootCA() || $this->hasIntermediateCA() || $this->hasCA();

tests/DTO/CertificateFlagTest.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,29 @@ public function testToString()
1414
$this->assertEquals('Root CA', CertificateFlag::ROOT_CA->toString());
1515
$this->assertEquals('Intermediate CA', CertificateFlag::INTERMEDIATE_CA->toString());
1616
$this->assertEquals('CA', CertificateFlag::CA->toString());
17-
$this->assertEquals('Document Signer', CertificateFlag::DOCUMENT_SIGNER->toString());
18-
$this->assertEquals('Template Signer', CertificateFlag::TEMPLATE_SIGNER->toString());
17+
$this->assertEquals('End Entity Flag 1', CertificateFlag::END_ENTITY_FLAG_1->toString());
18+
$this->assertEquals('End Entity Flag 2', CertificateFlag::END_ENTITY_FLAG_2->toString());
19+
$this->assertEquals('End Entity Flag 3', CertificateFlag::END_ENTITY_FLAG_3->toString());
20+
$this->assertEquals('End Entity Flag 4', CertificateFlag::END_ENTITY_FLAG_4->toString());
21+
$this->assertEquals('End Entity Flag 5', CertificateFlag::END_ENTITY_FLAG_5->toString());
22+
$this->assertEquals('End Entity Flag 6', CertificateFlag::END_ENTITY_FLAG_6->toString());
23+
$this->assertEquals('End Entity Flag 7', CertificateFlag::END_ENTITY_FLAG_7->toString());
24+
$this->assertEquals('End Entity Flag 8', CertificateFlag::END_ENTITY_FLAG_8->toString());
1925
}
2026

2127
public function testFromByte()
2228
{
2329
$this->assertEquals(CertificateFlag::ROOT_CA, CertificateFlag::fromByte(0x0001));
2430
$this->assertEquals(CertificateFlag::INTERMEDIATE_CA, CertificateFlag::fromByte(0x0002));
2531
$this->assertEquals(CertificateFlag::CA, CertificateFlag::fromByte(0x0004));
26-
$this->assertEquals(CertificateFlag::DOCUMENT_SIGNER, CertificateFlag::fromByte(0x0100));
27-
$this->assertEquals(CertificateFlag::TEMPLATE_SIGNER, CertificateFlag::fromByte(0x0200));
32+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_1, CertificateFlag::fromByte(0x0100));
33+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_2, CertificateFlag::fromByte(0x0200));
34+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_3, CertificateFlag::fromByte(0x0400));
35+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_4, CertificateFlag::fromByte(0x0800));
36+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_5, CertificateFlag::fromByte(0x1000));
37+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_6, CertificateFlag::fromByte(0x2000));
38+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_7, CertificateFlag::fromByte(0x4000));
39+
$this->assertEquals(CertificateFlag::END_ENTITY_FLAG_8, CertificateFlag::fromByte(0x8000));
2840

2941
try {
3042
CertificateFlag::fromByte(0xFFFF);

0 commit comments

Comments
 (0)