@@ -886,7 +886,20 @@ func writeEvidenceList(w *tabwriter.Writer, el mtc.EvidenceList) error {
886886 return nil
887887}
888888
889+ func handleVerify (cc * cli.Context ) error {
890+ return handleCert (cc , false )
891+ }
892+
889893func handleInspectCert (cc * cli.Context ) error {
894+ return handleCert (cc , true )
895+ }
896+
897+ // Handles `mtc verify' and `mtc inspect cert'
898+ func handleCert (cc * cli.Context , inspect bool ) error {
899+ if ! inspect && ! cc .IsSet ("validity-window" ) {
900+ return errors .New ("-validity-window must be set" )
901+ }
902+
890903 buf , err := inspectGetBuf (cc )
891904 if err != nil {
892905 return err
@@ -905,56 +918,95 @@ func handleInspectCert(cc *cli.Context) error {
905918 return err
906919 }
907920
908- w := tabwriter .NewWriter (os .Stdout , 1 , 1 , 1 , ' ' , 0 )
909- writeAssertion (w , c .Assertion )
910- fmt .Fprintf (w , "\n " )
911921 tai := c .Proof .TrustAnchorIdentifier ()
912- fmt .Fprintf (w , "proof_type\t %v\n " , tai .ProofType (& caStore ))
922+ if ! tai .Issuer .Equal (& params .Issuer ) {
923+ return fmt .Errorf (
924+ "Issuer in certificate (%s) does not match provided CA (%s)" ,
925+ tai .Issuer ,
926+ params .Issuer ,
927+ )
928+ }
929+
930+ var (
931+ vw * mtc.SignedValidityWindow
932+ verifyResult error
933+ )
934+ if cc .IsSet ("validity-window" ) {
935+ vwPath := cc .String ("validity-window" )
936+ vwBuf , err := os .ReadFile (vwPath )
937+ if err != nil {
938+ return fmt .Errorf ("Reading %s: %w" , vwPath , err )
939+ }
913940
914- fmt .Fprintf (w , "CA OID\t %s\n " , tai .Issuer )
915- fmt .Fprintf (w , "Batch number\t %d\n " , tai .BatchNumber )
941+ vw = new (mtc.SignedValidityWindow )
942+ if err := vw .UnmarshalBinary (vwBuf , params ); err != nil {
943+ return fmt .Errorf ("Parsing %s: %w" , vwPath , err )
944+ }
916945
917- switch proof := c .Proof .(type ) {
918- case * mtc.MerkleTreeProof :
919- fmt .Fprintf (w , "index\t %d\n " , proof .Index ())
946+ verifyResult = c .Verify (mtc.VerifyOptions {
947+ ValidityWindow : & vw .ValidityWindow ,
948+ CA : params ,
949+ })
920950 }
921951
922- switch proof := c .Proof .(type ) {
923- case * mtc.MerkleTreeProof :
924- path := proof .Path ()
925- batch := & mtc.Batch {
926- CA : params ,
927- Number : tai .BatchNumber ,
952+ if inspect {
953+ w := tabwriter .NewWriter (os .Stdout , 1 , 1 , 1 , ' ' , 0 )
954+ writeAssertion (w , c .Assertion )
955+ fmt .Fprintf (w , "\n " )
956+
957+ fmt .Fprintf (w , "proof_type\t %v\n " , params .ProofType )
958+ fmt .Fprintf (w , "CA TAI\t %s\n " , tai .Issuer )
959+ fmt .Fprintf (w , "Batch number\t %d\n " , tai .BatchNumber )
960+
961+ if vw != nil {
962+ vrs := "✅"
963+ if verifyResult != nil {
964+ vrs = verifyResult .Error ()
965+ }
966+
967+ fmt .Fprintf (w , "Verification result\t %s\n " , vrs )
928968 }
929969
930- if ! tai .Issuer .Equal (& params .Issuer ) {
931- return fmt .Errorf (
932- "IssuerId doesn't match: %s ≠ %s" ,
933- params .Issuer ,
934- tai .Issuer ,
970+ switch proof := c .Proof .(type ) {
971+ case * mtc.MerkleTreeProof :
972+ fmt .Fprintf (w , "index\t %d\n " , proof .Index ())
973+ path := proof .Path ()
974+ batch := & mtc.Batch {
975+ CA : params ,
976+ Number : tai .BatchNumber ,
977+ }
978+
979+ if ! tai .Issuer .Equal (& params .Issuer ) {
980+ return fmt .Errorf (
981+ "IssuerId doesn't match: %s ≠ %s" ,
982+ params .Issuer ,
983+ tai .Issuer ,
984+ )
985+ }
986+ be := mtc .NewBatchEntry (c .Assertion , proof .NotAfter ())
987+ head , err := batch .ComputeTreeHeadFromAuthenticationPath (
988+ proof .Index (),
989+ path ,
990+ & be ,
935991 )
936- }
937- be := mtc .NewBatchEntry (c .Assertion , proof .NotAfter ())
938- head , err := batch .ComputeTreeHeadFromAuthenticationPath (
939- proof .Index (),
940- path ,
941- & be ,
942- )
943- if err != nil {
944- return fmt .Errorf ("computing tree head: %w" , err )
945- }
992+ if err != nil {
993+ return fmt .Errorf ("computing tree head: %w" , err )
994+ }
946995
947- fmt .Fprintf (w , "recomputed tree head\t %x\n " , head )
996+ fmt .Fprintf (w , "recomputed tree head\t %x\n " , head )
948997
949- w .Flush ()
950- fmt .Printf ("authentication path\n " )
951- for i := 0 ; i < len (path )/ mtc .HashLen ; i ++ {
952- fmt .Printf (" %x\n " , path [i * mtc .HashLen :(i + 1 )* mtc .HashLen ])
998+ w .Flush ()
999+ fmt .Printf ("authentication path\n " )
1000+ for i := 0 ; i < len (path )/ mtc .HashLen ; i ++ {
1001+ fmt .Printf (" %x\n " , path [i * mtc .HashLen :(i + 1 )* mtc .HashLen ])
1002+ }
9531003 }
1004+
1005+ w .Flush ()
1006+ return nil
9541007 }
9551008
956- w .Flush ()
957- return nil
1009+ return verifyResult
9581010}
9591011
9601012func handleInspectAssertionRequest (cc * cli.Context ) error {
@@ -1322,6 +1374,13 @@ func main() {
13221374 Usage : "parses a certificate" ,
13231375 Action : handleInspectCert ,
13241376 ArgsUsage : "[path]" ,
1377+ Flags : []cli.Flag {
1378+ & cli.StringFlag {
1379+ Name : "validity-window" ,
1380+ Usage : "path to signed validity window to verify against" ,
1381+ Aliases : []string {"w" },
1382+ },
1383+ },
13251384 },
13261385 {
13271386 Name : "umbilical-certificates" ,
@@ -1358,6 +1417,24 @@ func main() {
13581417 },
13591418 ),
13601419 },
1420+ {
1421+ Name : "verify" ,
1422+ Usage : "verifies a merkle tree certificate" ,
1423+ Action : handleVerify ,
1424+ ArgsUsage : "[path]" ,
1425+ Flags : []cli.Flag {
1426+ & cli.StringFlag {
1427+ Name : "ca-params" ,
1428+ Usage : "path to CA parameters" ,
1429+ Aliases : []string {"p" },
1430+ },
1431+ & cli.StringFlag {
1432+ Name : "validity-window" ,
1433+ Usage : "path to trusted signed validity window" ,
1434+ Aliases : []string {"w" },
1435+ },
1436+ },
1437+ },
13611438 },
13621439 Before : func (cc * cli.Context ) error {
13631440 if path := cc .String ("cpuprofile" ); path != "" {
0 commit comments