Skip to content

Commit 3b8937a

Browse files
leopoldjoyOpenCode
andcommitted
fix: require exact cert signature wrapper
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
1 parent c0a9f21 commit 3b8937a

2 files changed

Lines changed: 69 additions & 0 deletions

File tree

src/CertManager.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,17 @@ contract CertManager is ICertManager {
557557
function _certSignature(bytes memory certificate, Asn1Ptr sigPtr) internal pure returns (bytes memory sigPacked) {
558558
Asn1Ptr sigBPtr = certificate.bitstring(sigPtr);
559559
Asn1Ptr sigRoot = certificate.rootOf(sigBPtr);
560+
require(certificate[sigRoot.header()] == 0x30, "invalid cert signature");
561+
require(
562+
sigRoot.header() + sigRoot.totalLength() == sigBPtr.content() + sigBPtr.length(), "invalid cert signature"
563+
);
560564
Asn1Ptr sigRPtr = certificate.firstChildOf(sigRoot);
565+
require(certificate[sigRPtr.header()] == 0x02, "invalid cert signature");
561566
Asn1Ptr sigSPtr = certificate.nextSiblingOf(sigRPtr);
567+
require(certificate[sigSPtr.header()] == 0x02, "invalid cert signature");
568+
require(
569+
sigSPtr.header() + sigSPtr.totalLength() == sigRoot.content() + sigRoot.length(), "invalid cert signature"
570+
);
562571
(uint128 rhi, uint256 rlo) = certificate.uint384At(sigRPtr);
563572
(uint128 shi, uint256 slo) = certificate.uint384At(sigSPtr);
564573
sigPacked = abi.encodePacked(rhi, rlo, shi, slo);

test/CertManager.t.sol

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,38 @@ contract CertManagerTest is Test {
166166
cm.verifyCACertWithHints(rootTwin, rootHash, hints);
167167
}
168168

169+
function test_VerifyCACertWithHints_RejectsSignatureWrapperTagSubstitution() public {
170+
vm.warp(1775145600);
171+
CertManager cm = new CertManager(new P384Verifier());
172+
P384HintCollector collector = new P384HintCollector();
173+
174+
bytes32 rootHash = keccak256(CB0);
175+
bytes memory parentPubKey = cm.loadVerified(rootHash).pubKey;
176+
bytes memory hints = collector.collectCertSignatureHints(CB1, parentPubKey);
177+
178+
bytes memory mutated = bytes.concat(CB1);
179+
(,, Asn1Ptr sigRoot,) = _certSignaturePtrs(mutated);
180+
mutated[sigRoot.header()] = 0x31; // constructed SET with the same r/s children.
181+
182+
vm.expectRevert("invalid cert signature");
183+
cm.verifyCACertWithHints(mutated, rootHash, hints);
184+
}
185+
186+
function test_VerifyCACertWithHints_RejectsTrailingSignatureFields() public {
187+
vm.warp(1775145600);
188+
CertManager cm = new CertManager(new P384Verifier());
189+
P384HintCollector collector = new P384HintCollector();
190+
191+
bytes32 rootHash = keccak256(CB0);
192+
bytes memory parentPubKey = cm.loadVerified(rootHash).pubKey;
193+
bytes memory hints = collector.collectCertSignatureHints(CB1, parentPubKey);
194+
195+
bytes memory mutated = _appendSignatureTrailingField(CB1);
196+
197+
vm.expectRevert("invalid cert signature");
198+
cm.verifyCACertWithHints(mutated, rootHash, hints);
199+
}
200+
169201
function _verifyCA(CertManager cm, P384HintCollector collector, bytes memory cert, bytes32 parentHash)
170202
internal
171203
returns (bytes32)
@@ -212,6 +244,34 @@ contract CertManagerTest is Test {
212244
_writeDerLength(result, sigRoot, _addDelta(sigRoot.length(), delta));
213245
}
214246

247+
function _appendSignatureTrailingField(bytes memory certificate) internal pure returns (bytes memory result) {
248+
(Asn1Ptr root, Asn1Ptr sigPtr, Asn1Ptr sigRoot,) = _certSignaturePtrs(certificate);
249+
bytes memory extraInteger = hex"020100";
250+
int256 delta = int256(extraInteger.length);
251+
result = _insertBytes(certificate, sigRoot.content() + sigRoot.length(), extraInteger);
252+
253+
_writeDerLength(result, root, _addDelta(root.length(), delta));
254+
_writeDerLength(result, sigPtr, _addDelta(sigPtr.length(), delta));
255+
_writeDerLength(result, sigRoot, _addDelta(sigRoot.length(), delta));
256+
}
257+
258+
function _insertBytes(bytes memory input, uint256 offset, bytes memory inserted)
259+
internal
260+
pure
261+
returns (bytes memory result)
262+
{
263+
result = new bytes(input.length + inserted.length);
264+
for (uint256 i = 0; i < offset; ++i) {
265+
result[i] = input[i];
266+
}
267+
for (uint256 i = 0; i < inserted.length; ++i) {
268+
result[offset + i] = inserted[i];
269+
}
270+
for (uint256 i = offset; i < input.length; ++i) {
271+
result[i + inserted.length] = input[i];
272+
}
273+
}
274+
215275
function _certSignaturePtrs(bytes memory certificate)
216276
internal
217277
pure

0 commit comments

Comments
 (0)