Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions src/CertManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ contract CertManager is ICertManager {
using LibAsn1Ptr for Asn1Ptr;
using LibBytes for bytes;

error InvalidCertSignature();

event CertVerified(bytes32 indexed certHash);
event CertRevoked(bytes32 indexed certHash);
event CertUnrevoked(bytes32 indexed certHash);
Expand Down Expand Up @@ -557,8 +559,17 @@ contract CertManager is ICertManager {
function _certSignature(bytes memory certificate, Asn1Ptr sigPtr) internal pure returns (bytes memory sigPacked) {
Asn1Ptr sigBPtr = certificate.bitstring(sigPtr);
Asn1Ptr sigRoot = certificate.rootOf(sigBPtr);
if (certificate[sigRoot.header()] != 0x30) revert InvalidCertSignature();
if (sigRoot.header() + sigRoot.totalLength() != sigBPtr.content() + sigBPtr.length()) {
revert InvalidCertSignature();
}
Asn1Ptr sigRPtr = certificate.firstChildOf(sigRoot);
if (certificate[sigRPtr.header()] != 0x02) revert InvalidCertSignature();
Asn1Ptr sigSPtr = certificate.nextSiblingOf(sigRPtr);
if (certificate[sigSPtr.header()] != 0x02) revert InvalidCertSignature();
if (sigSPtr.header() + sigSPtr.totalLength() != sigRoot.content() + sigRoot.length()) {
revert InvalidCertSignature();
}
(uint128 rhi, uint256 rlo) = certificate.uint384At(sigRPtr);
(uint128 shi, uint256 slo) = certificate.uint384At(sigSPtr);
sigPacked = abi.encodePacked(rhi, rlo, shi, slo);
Expand Down
60 changes: 60 additions & 0 deletions test/CertManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,38 @@ contract CertManagerTest is Test {
cm.verifyCACertWithHints(rootTwin, rootHash, hints);
}

function test_VerifyCACertWithHints_RejectsSignatureWrapperTagSubstitution() public {
vm.warp(1775145600);
CertManager cm = new CertManager(new P384Verifier());
P384HintCollector collector = new P384HintCollector();

bytes32 rootHash = keccak256(CB0);
bytes memory parentPubKey = cm.loadVerified(rootHash).pubKey;
bytes memory hints = collector.collectCertSignatureHints(CB1, parentPubKey);

bytes memory mutated = bytes.concat(CB1);
(,, Asn1Ptr sigRoot,) = _certSignaturePtrs(mutated);
mutated[sigRoot.header()] = 0x31; // constructed SET with the same r/s children.

vm.expectRevert(CertManager.InvalidCertSignature.selector);
cm.verifyCACertWithHints(mutated, rootHash, hints);
}

function test_VerifyCACertWithHints_RejectsTrailingSignatureFields() public {
vm.warp(1775145600);
CertManager cm = new CertManager(new P384Verifier());
P384HintCollector collector = new P384HintCollector();

bytes32 rootHash = keccak256(CB0);
bytes memory parentPubKey = cm.loadVerified(rootHash).pubKey;
bytes memory hints = collector.collectCertSignatureHints(CB1, parentPubKey);

bytes memory mutated = _appendSignatureTrailingField(CB1);

vm.expectRevert(CertManager.InvalidCertSignature.selector);
cm.verifyCACertWithHints(mutated, rootHash, hints);
}

function _verifyCA(CertManager cm, P384HintCollector collector, bytes memory cert, bytes32 parentHash)
internal
returns (bytes32)
Expand Down Expand Up @@ -212,6 +244,34 @@ contract CertManagerTest is Test {
_writeDerLength(result, sigRoot, _addDelta(sigRoot.length(), delta));
}

function _appendSignatureTrailingField(bytes memory certificate) internal pure returns (bytes memory result) {
(Asn1Ptr root, Asn1Ptr sigPtr, Asn1Ptr sigRoot,) = _certSignaturePtrs(certificate);
bytes memory extraInteger = hex"020100";
int256 delta = int256(extraInteger.length);
result = _insertBytes(certificate, sigRoot.content() + sigRoot.length(), extraInteger);

_writeDerLength(result, root, _addDelta(root.length(), delta));
_writeDerLength(result, sigPtr, _addDelta(sigPtr.length(), delta));
_writeDerLength(result, sigRoot, _addDelta(sigRoot.length(), delta));
}

function _insertBytes(bytes memory input, uint256 offset, bytes memory inserted)
internal
pure
returns (bytes memory result)
{
result = new bytes(input.length + inserted.length);
for (uint256 i = 0; i < offset; ++i) {
result[i] = input[i];
}
for (uint256 i = 0; i < inserted.length; ++i) {
result[offset + i] = inserted[i];
}
for (uint256 i = offset; i < input.length; ++i) {
result[i + inserted.length] = input[i];
}
}

function _certSignaturePtrs(bytes memory certificate)
internal
pure
Expand Down
Loading