From 321e8cc094e6e78dc7eb5e74b87dea30d4272148 Mon Sep 17 00:00:00 2001 From: Bob Hageman Date: Tue, 24 Oct 2023 09:20:13 +0200 Subject: [PATCH 1/2] feat: add irma cmd option to prolong keys --- irma/cmd/prolong.go | 132 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 irma/cmd/prolong.go diff --git a/irma/cmd/prolong.go b/irma/cmd/prolong.go new file mode 100644 index 00000000..914cea4d --- /dev/null +++ b/irma/cmd/prolong.go @@ -0,0 +1,132 @@ +package cmd + +import ( + "fmt" + "path/filepath" + "regexp" + "strconv" + "strings" + + "os" + + "github.com/privacybydesign/irmago/internal/common" + "github.com/spf13/cobra" +) + +var prolongCmd = &cobra.Command{ + Use: "prolong [] []", + Short: "Prolong expiring public and private keys so they are at least valid until the specified timestamp", + Long: "The prolong command updates the latest public and private keys by setting to the specified timestamp for keys which expire before that timestamp.\n\n", + Run: func(cmd *cobra.Command, args []string) { + + if len(args) < 2 { + die("Invalid arguments given", nil) + } + + path := args[0] + exists, err := common.PathExists(path) + if err != nil || !exists { + die("Could not check path existence", err) + } + + timestamp, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + die("Invalid timestamp", err) + } + + keys, err := findHighestKeys(path) + if err != nil { + die("Could not find keys", err) + } + + for _, key := range keys { + updateExpiryDate(key, timestamp) + } + }, +} + +func findHighestKeys(path string) ([]string, error) { + var items []string + + if err := filepath.Walk(path, func(path string, file os.FileInfo, err error) error { + if err != nil { + return err + } + + if !file.IsDir() { + + // Is this a key? + if r, err := regexp.MatchString("[0-999].xml", file.Name()); err != nil || !r { + return err + } + + // Get the key number to be able to determine if there is a higher key number available + keyNr, err := strconv.ParseInt(strings.Split(file.Name(), ".")[0], 10, 64) + if err != nil { + return err + } + + nextKey := filepath.Dir(path) + "/" + strconv.FormatInt(keyNr+1, 10) + ".xml" + exists, err := common.PathExists(nextKey) + if err != nil || exists { + // There is a higher key number available in the same folder so we skip this one + return err + } + + absPath, err := filepath.Abs(path) + if err != nil { + return err + } + + items = append(items, absPath) + + } + return nil + }); err != nil { + return nil, err + } + + return items, nil +} + +func updateExpiryDate(file string, timestamp int64) error { + pubKey, err := os.ReadFile(file) + if err != nil { + return err + } + + regex, err := regexp.Compile("()(.*?)()") + if err != nil { + return err + } + + matches := regex.FindSubmatch(pubKey) + if len(matches) == 0 { + return nil + } + + currTimestamp, err := strconv.ParseInt(string(matches[2]), 10, 64) + if err != nil { + return err + } + + if currTimestamp >= timestamp { + // Does not expire before given timestamp + return nil + } + + replace := regex.ReplaceAllString(string(pubKey), "${1}"+strconv.FormatInt(timestamp, 10)+"${3}") + + err = os.WriteFile(file, []byte(replace), 0644) + if err != nil { + return err + } + + fmt.Printf("Prolonged key: %s\n", file) + + return nil +} + +func init() { + schemeCmd.AddCommand(prolongCmd) +} From 9e7ee94925e1d00fadc79f5bb9ad8e07d1e29099 Mon Sep 17 00:00:00 2001 From: Bob Hageman Date: Mon, 13 Nov 2023 15:11:02 +0100 Subject: [PATCH 2/2] improve: skip prolongation for deprecated issuers --- irma/cmd/prolong.go | 93 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/irma/cmd/prolong.go b/irma/cmd/prolong.go index 914cea4d..fbc77bc3 100644 --- a/irma/cmd/prolong.go +++ b/irma/cmd/prolong.go @@ -16,7 +16,7 @@ import ( var prolongCmd = &cobra.Command{ Use: "prolong [] []", Short: "Prolong expiring public and private keys so they are at least valid until the specified timestamp", - Long: "The prolong command updates the latest public and private keys by setting to the specified timestamp for keys which expire before that timestamp.\n\n", + Long: "The prolong command updates the latest public and private keys for non deprecated issuers by setting to the specified timestamp for keys which expire before that timestamp.\n\n", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { @@ -40,13 +40,25 @@ var prolongCmd = &cobra.Command{ } for _, key := range keys { - updateExpiryDate(key, timestamp) + + // Is this key part of a deprecated issuer? + deprecated, err := deprecated(key, timestamp) + + if err != nil { + die("Could not check if key is deprecated", err) + } + + if !deprecated { + updateExpiryDate(key, timestamp) + } else { + fmt.Printf("Skipping deprecated key: %s\n", key) + } } }, } func findHighestKeys(path string) ([]string, error) { - var items []string + var keys []string if err := filepath.Walk(path, func(path string, file os.FileInfo, err error) error { if err != nil { @@ -78,55 +90,94 @@ func findHighestKeys(path string) ([]string, error) { return err } - items = append(items, absPath) - + keys = append(keys, absPath) } return nil }); err != nil { return nil, err } - return items, nil + return keys, nil } -func updateExpiryDate(file string, timestamp int64) error { - pubKey, err := os.ReadFile(file) - if err != nil { - return err - } +// Is this key part of a deprecated issuer? +func deprecated(file string, timestamp int64) (bool, error) { - regex, err := regexp.Compile("()(.*?)()") + descriptionFile := filepath.Dir(file) + "/../description.xml" + + foundTimestamp, err := findTimestamp(descriptionFile, "()(.*?)()") if err != nil { - return err + return false, err } - matches := regex.FindSubmatch(pubKey) - if len(matches) == 0 { - return nil + if foundTimestamp == 0 || foundTimestamp >= timestamp { + // Is not deprecated or does not become deprecated before given timestamp + return false, nil } - currTimestamp, err := strconv.ParseInt(string(matches[2]), 10, 64) + return true, nil +} + +func updateExpiryDate(file string, timestamp int64) error { + foundTimestamp, err := findTimestamp(file, "()(.*?)()") if err != nil { return err } - if currTimestamp >= timestamp { + if foundTimestamp >= timestamp { // Does not expire before given timestamp return nil } - replace := regex.ReplaceAllString(string(pubKey), "${1}"+strconv.FormatInt(timestamp, 10)+"${3}") + if err := replaceTimestamp(file, + ""+strconv.FormatInt(foundTimestamp, 10)+"", + ""+strconv.FormatInt(timestamp, 10)+""); err != nil { + return err + } + + fmt.Printf("Prolonged key: %s\n", file) + + return nil +} - err = os.WriteFile(file, []byte(replace), 0644) +func replaceTimestamp(file string, find string, replace string) error { + bytes, err := os.ReadFile(file) if err != nil { return err } - fmt.Printf("Prolonged key: %s\n", file) + result := strings.ReplaceAll(string(bytes), find, replace) + + if err := os.WriteFile(file, []byte(result), 0644); err != nil { + return err + } return nil } +func findTimestamp(file string, pattern string) (int64, error) { + bytes, err := os.ReadFile(file) + if err != nil { + return 0, err + } + + regex, err := regexp.Compile(pattern) + if err != nil { + return 0, err + } + + matches := regex.FindSubmatch(bytes) + if len(matches) == 0 { + return 0, nil + } + + timestamp, err := strconv.ParseInt(string(matches[2]), 10, 64) + if err != nil { + return 0, err + } + return timestamp, nil +} + func init() { schemeCmd.AddCommand(prolongCmd) }