issuer-keyverify.go 3.51 KB
Newer Older
1
2
3
4
5
6
package cmd

import (
	"compress/gzip"
	"encoding/json"
	"fmt"
7
	"io"
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	"os"
	"path/filepath"
	"strconv"

	"github.com/privacybydesign/gabi"
	"github.com/privacybydesign/gabi/keyproof"
	"github.com/privacybydesign/irmago/internal/common"
	"github.com/sietseringers/cobra"
)

var issuerKeyverifyCmd = &cobra.Command{
	Use:   "keyverify [path]",
	Short: "Verify validity proof for an IRMA issuer keypair",
	Long: `Verify validity proof for an IRMA issuer keypair.

The keyverify command verifies proofs of validity for IRMA issuer keys. By default, it verifies the newest proof in the Proofs folder, matching it to the corresponding key in PublicKeys.`,
	Args: cobra.MaximumNArgs(1),
25
	Run: func(cmd *cobra.Command, args []string) {
26
27
28
29
30
31
32
33
34
35
36
37
38
39
		flags := cmd.Flags()
		counter, _ := flags.GetUint("counter")
		pubkeyfile, _ := flags.GetString("publickey")
		prooffile, _ := flags.GetString("proof")

		var err error

		// Determine path for key
		var path string
		if len(args) != 0 {
			path = args[0]
		} else {
			path, err = os.Getwd()
			if err != nil {
40
				die("", err)
41
42
43
			}
		}
		if err = common.AssertPathExists(path); err != nil {
44
			die("Nonexisting path specified", err)
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
		}

		// Determine counter if needed
		if !flags.Changed("counter") {
			counter = uint(lastProofIndex(path))
		}

		// Fill in pubkey if needed
		if pubkeyfile == "" {
			pubkeyfile = filepath.Join(path, "PublicKeys", strconv.Itoa(int(counter))+".xml")
		}

		// Fill in proof if needed
		if prooffile == "" {
			prooffile = filepath.Join(path, "Proofs", strconv.Itoa(int(counter))+".json.gz")
		}

		// Try to read public key
		pk, err := gabi.NewPublicKeyFromFile(pubkeyfile)
		if err != nil {
65
			die("Error reading public key", err)
66
67
68
69
70
71
72
73
74
75
76
77
78
79
		}

		// Start log follower
		follower := startLogFollower()
		defer func() {
			follower.quitEvents <- quitMessage{}
			<-follower.finished
		}()

		// Try to read proof
		follower.StepStart("Reading proofdata", 0)
		proofFile, err := os.Open(prooffile)
		if err != nil {
			follower.StepDone()
80
			die("Error opening proof", err)
81
		}
82
		defer closeCloser(proofFile)
83
84
85
		proofGzip, err := gzip.NewReader(proofFile)
		if err != nil {
			follower.StepDone()
86
			die("Error reading proof data", err)
87
		}
88
		defer closeCloser(proofGzip)
89
90
91
92
93
		proofDecoder := json.NewDecoder(proofGzip)
		var proof keyproof.ValidKeyProof
		err = proofDecoder.Decode(&proof)
		if err != nil {
			follower.StepDone()
94
			die("Error reading proof data", err)
95
96
97
98
99
100
101
102
		}
		follower.StepDone()

		// Construct proof structure
		s := keyproof.NewValidKeyProofStructure(pk.N, pk.Z, pk.S, pk.R)

		// And use it to validate the proof
		if !s.VerifyProof(proof) {
103
			die("Proof is invalid!", nil)
104
105
106
107
108
109
		} else {
			follower.finalEvents <- setFinalMessage{"Proof is valid"}
		}
	},
}

110
111
112
113
114
115
func closeCloser(c io.Closer) {
	if err := c.Close(); err != nil {
		die("", err)
	}
}

116
117
118
119
func lastProofIndex(path string) (counter int) {
	matches, _ := filepath.Glob(filepath.Join(path, "Proofs", "*.json.gz"))
	for _, match := range matches {
		filename := filepath.Base(match)
120
		c, err := strconv.Atoi(filename[:len(filename)-8])
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
		if err != nil {
			fmt.Println(err.Error())
			continue
		}
		if c > counter {
			counter = c
		}
	}
	return
}

func init() {
	issuerCmd.AddCommand(issuerKeyverifyCmd)

	issuerKeyverifyCmd.Flags().StringP("publickey", "p", "", `File of public key to verify (default "PublicKeys/$index.xml")`)
	issuerKeyverifyCmd.Flags().StringP("proof", "o", "", `File of proof to verify (default "Proofs/$counter.json.gz")`)
	issuerKeyverifyCmd.Flags().UintP("counter", "c", 0, "Counter of key to verify (default to latest with proof)")
}