Skip to content

Commit

Permalink
Merge pull request #660 from sigstore/verify-checkpoints
Browse files Browse the repository at this point in the history
Add checkpoint verification
  • Loading branch information
loosebazooka authored Mar 26, 2024
2 parents 9170121 + 5aba06b commit 9ec514d
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public void verify(byte[] artifactDigest, KeylessVerificationRequest request)
try {
rekorVerifier.verifyEntry(rekorEntry);
} catch (RekorVerificationException ex) {
throw new KeylessVerificationException("Rekor entry signature was not valid");
throw new KeylessVerificationException("Rekor entry signature was not valid", ex);
}

// check if the time of entry inclusion in the log (a stand-in for signing time) is within the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@

import com.google.common.hash.Hashing;
import dev.sigstore.encryption.signers.Verifiers;
import dev.sigstore.rekor.client.RekorEntry.Checkpoint;
import dev.sigstore.trustroot.SigstoreTrustedRoot;
import dev.sigstore.trustroot.TransparencyLog;
import dev.sigstore.trustroot.TransparencyLogs;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Base64;
import org.bouncycastle.util.encoders.Hex;

Expand Down Expand Up @@ -84,6 +87,7 @@ public void verifyEntry(RekorEntry entry) throws RekorVerificationException {

// verify inclusion proof
verifyInclusionProof(entry);
verifyCheckpoint(entry, tlog);
}

/** Verify that a Rekor Entry is in the log by checking inclusion proof. */
Expand Down Expand Up @@ -134,6 +138,43 @@ private void verifyInclusionProof(RekorEntry entry) throws RekorVerificationExce
}
}

private void verifyCheckpoint(RekorEntry entry, TransparencyLog tlog)
throws RekorVerificationException {
Checkpoint checkpoint;
try {
checkpoint = entry.getVerification().getInclusionProof().parsedCheckpoint();
} catch (RekorParseException ex) {
throw new RekorVerificationException("Could not parse checkpoint", ex);
}

byte[] inclusionRootHash =
Hex.decode(entry.getVerification().getInclusionProof().getRootHash());
byte[] checkpointRootHash = Base64.getDecoder().decode(checkpoint.getBase64Hash());

if (!Arrays.equals(inclusionRootHash, checkpointRootHash)) {
throw new RekorVerificationException(
"Checkpoint root hash does not match root hash provided in inclusion proof");
}
var keyHash = Hashing.sha256().hashBytes(tlog.getPublicKey().getRawBytes()).asBytes();
// checkpoint 0 is always the log, not any of the cross signing verifiers/monitors
var sig = checkpoint.getSignatures().get(0);
for (int i = 0; i < 4; i++) {
if (sig.getKeyHint()[i] != keyHash[i]) {
throw new RekorVerificationException(
"Checkpoint key hint did not match provided log public key");
}
}
try {
Verifiers.newVerifier(tlog.getPublicKey().toJavaPublicKey())
.verifyDigest(inclusionRootHash, sig.getSignature());
} catch (NoSuchAlgorithmException
| InvalidKeySpecException
| SignatureException
| InvalidKeyException ex) {
throw new RekorVerificationException("Could not verify checkpoint signature", ex);
}
}

private static byte[] combineBytes(byte[] first, byte[] second) {
byte[] result = new byte[first.length + second.length];
System.arraycopy(first, 0, result, 0, first.length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,23 @@
"67e9d9f66f0ad388f7e1a20991e9a2ae3efad5cbf281e8b3d2aaf1ef99a4618c",
"16a106400c53465f6e18c2475df6ba889ca30f5667bacf32b1a5661f14a5080c",
"b4439e8d71edbc96271723cb7a969dd725e23e73d139361864a62ed76ce8dc11",
"f4926d3efb0abd42b18e18372886854825a2b378e249bd333f81d8d4534485c4",
"49b3e90806c7b63b5a86f5748e3ecb7d264ea0828eb74a45bc1a2cd7962408e8",
"5059ad9b48fa50bd9adcbff0dd81c5a0dcb60f37e0716e723a33805a464f72f8",
"6c2ce64219799e61d72996884eee9e19fb906e4d7fa04b71625fde4108f21762",
"784f79c817abb78db3ae99b6c1ede640470bf4bb678673a05bf3a6b50aaaddd6",
"0da021f68571b65e49e926e4c69024de3ac248a1319d254bc51a85a657b93c33"
"c6d92ebf4e10cdba500ca410166cd0a8d8b312154d2f45bc4292d63dea6112f6",
"1768732027401f6718b0df7769e2803127cfc099eb130a8ed7d913218f6a65f6",
"0da021f68571b65e49e926e4c69024de3ac248a1319d254bc51a85a657b93c33",
"bc8cf0c8497d5c24841de0c9bef598ec99bbd59d9538d58568340646fe289e9a",
"be328fa737b8fa9461850b8034250f237ff5b0b590b9468e6223968df294872b",
"6f06f4025d0346f04830352b23f65c8cd9e3ce4b8cb899877c35282521ddaf85"
],
"logIndex": 1227,
"rootHash": "c2aaeaf36d5899ee2ab6d931bdc39d0c50e6a9dccee0322b6a9483538f4ef079",
"checkpoint": "The checkpoint (signed tree head) that the inclusion proof is based on",
"treeSize": 1237
"rootHash": "effa4fa4575f72829016a64e584441203de533212f9470d63a56d1992e73465d",
"treeSize": 14358,
"checkpoint": "rekor.sigstage.dev - 108574341321668964\n14358\n7/pPpFdfcoKQFqZOWERBID3lMyEvlHDWOlbRmS5zRl0=\n\n— rekor.sigstage.dev 0y8wozBFAiB8OkuzdwlL6/rDEu2CsIfqmesaH/KLfmIMvlH3YTdIYgIhAPFZeXK6+b0vbWy4GSU/YZxiTpFrrzjsVOShN4LlPdZb\n"
},
"signedEntryTimestamp": "MEUCIAM2WgNNS1xwUBuoX/rYUBxbyKa6PVwNakss5KJzxw4jAiEA1//71yKdbHUi+rZRX7UyWBf4yBRp1vrkvOcWx6bbqfY="
"signedEntryTimestamp": "MEUCIQCO8dFvolJwFZDHkhkSdsW3Ny+07fG8CF7G32feG8NJMgIgd2qfJ5shezuXX8I1S6DsudvIZ8xN/+y95at/V5xHfEQ="
}
}
}

0 comments on commit 9ec514d

Please sign in to comment.