func computeSignature(a mig.Action, ctx Context) (pgpsig string, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("computeSignature() -> %v", e) } }() // do a round trip through the json marshaller, this is voodoo that // fixes signature verification issues down the road b, err := json.Marshal(a) if err != nil { panic(err) } err = json.Unmarshal(b, &a) if err != nil { panic(err) } secringFile, err := os.Open(ctx.GPG.Home + "/secring.gpg") if err != nil { panic(err) } defer secringFile.Close() // compute the signature str, err := a.String() if err != nil { panic(err) } pgpsig, err = sign.Sign(str, ctx.GPG.KeyID, secringFile) if err != nil { panic(err) } fmt.Println("Signature computed successfully") return }
func main() { var Usage = func() { fmt.Fprintf(os.Stderr, "Mozilla InvestiGator Action Generator\n"+ "usage: %s -k=<key id> (-i <input file)\n\n"+ "Command line to generate and sign MIG Actions.\n"+ "The resulting actions are display on stdout.\n\n"+ "Options:\n", os.Args[0]) flag.PrintDefaults() } // command line options var key = flag.String("k", "key identifier", "Key identifier used to sign the action (ex: B75C2346)") var pretty = flag.Bool("p", false, "Print signed action in pretty JSON format") var urlencode = flag.Bool("urlencode", false, "URL Encode marshalled JSON before output") var posturl = flag.String("posturl", "", "POST action to <url> (enforces urlencode)") var file = flag.String("i", "/path/to/file", "Load action from file") var target = flag.String("t", "some.target.example.net", "Set the target of the action") var validfrom = flag.String("validfrom", "now", "(optional) set an ISO8601 date the action will be valid from. If unset, use 'now'.") var expireafter = flag.String("expireafter", "30m", "(optional) set a validity duration for the action. If unset, use '30m'.") flag.Parse() // We need a key, if none is set on the command line, fail if *key == "key identifier" { Usage() os.Exit(-1) } var err error // if a file is defined, load action from that if *file == "/path/to/file" { fmt.Println("Missing action file") os.Exit(1) } a, err := mig.ActionFromFile(*file) if err != nil { panic(err) } // set the dates if *validfrom == "now" { // for immediate execution, set validity one minute in the past a.ValidFrom = time.Now().Add(-60 * time.Second).UTC() } else { a.ValidFrom, err = time.Parse("2014-01-01T00:00:00.0Z", *validfrom) if err != nil { panic(err) } } period, err := time.ParseDuration(*expireafter) if err != nil { log.Fatal(err) } a.ExpireAfter = a.ValidFrom.Add(period) if *target != "some.target.example.net" { a.Target = *target } // find homedir var homedir string if runtime.GOOS == "darwin" { homedir = os.Getenv("HOME") } else { // find keyring in default location u, err := user.Current() if err != nil { panic(err) } homedir = u.HomeDir } // load keyrings var gnupghome string gnupghome = os.Getenv("GNUPGHOME") if gnupghome == "" { gnupghome = "/.gnupg" } pubringFile, err := os.Open(homedir + gnupghome + "/pubring.gpg") if err != nil { panic(err) } defer pubringFile.Close() secringFile, err := os.Open(homedir + gnupghome + "/secring.gpg") if err != nil { panic(err) } defer secringFile.Close() // compute the signature str, err := a.String() if err != nil { panic(err) } pgpsig, err := sign.Sign(str, *key, secringFile) if err != nil { panic(err) } // store the signature in the action signature array a.PGPSignatures = append(a.PGPSignatures, pgpsig) // syntax checking err = a.Validate() if err != nil { panic(err) } // signature checking err = a.VerifySignatures(pubringFile) if err != nil { panic(err) } // if asked, pretty print the action var jsonAction []byte if *pretty { jsonAction, err = json.MarshalIndent(a, "", "\t") fmt.Printf("%s\n", jsonAction) } else { jsonAction, err = json.Marshal(a) } if err != nil { panic(err) } // if asked, url encode the action before marshaling it actionstr := string(jsonAction) if *urlencode { strJsonAction := string(jsonAction) actionstr = url.QueryEscape(strJsonAction) if *pretty { fmt.Println(actionstr) } } // http post the action to the posturl endpoint if *posturl != "" { resp, err := http.PostForm(*posturl, url.Values{"action": {actionstr}}) defer resp.Body.Close() if err != nil { panic(err) } body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } fmt.Printf("%s", body) } }
func main() { var Usage = func() { fmt.Fprintf(os.Stderr, "Mozilla InvestiGator Action Generator\n"+ "usage: %s -k=<key id> (-i <input file)\n\n"+ "Command line to generate and sign MIG Actions.\n"+ "The resulting actions are display on stdout.\n\n"+ "Options:\n", os.Args[0]) flag.PrintDefaults() } // command line options var key = flag.String("k", "key identifier", "Key identifier used to sign the action (ex: B75C2346)") var pretty = flag.Bool("p", false, "Print signed action in pretty JSON format") var urlencode = flag.Bool("urlencode", false, "URL Encode marshalled JSON before output") var posturl = flag.String("posturl", "", "POST action to <url> (enforces urlencode)") var file = flag.String("i", "/path/to/file", "Load action from file") var validfrom = flag.String("validfrom", "now", "(optional) set an ISO8601 date the action will be valid from. If unset, use 'now'.") var expireafter = flag.String("expireafter", "30m", "(optional) set a validity duration for the action. If unset, use '30m'.") flag.Parse() // We need a key, if none is set on the command line, fail if *key == "key identifier" { Usage() os.Exit(-1) } var a mig.Action var err error // if a file is defined, load action from that if *file != "/path/to/file" { a, err = mig.ActionFromFile(*file) } else { // otherwise, use interactive mode a, err = getActionFromTerminal() } if err != nil { panic(err) } // set the dates if *validfrom == "now" { a.ValidFrom = time.Now().UTC() } else { a.ValidFrom, err = time.Parse("2014-01-01T00:00:00.0Z", *validfrom) if err != nil { panic(err) } } period, err := time.ParseDuration(*expireafter) if err != nil { log.Fatal(err) } a.ExpireAfter = a.ValidFrom.Add(period) // compute the signature str, err := a.String() if err != nil { panic(err) } a.PGPSignature, err = sign.Sign(str, *key) if err != nil { panic(err) } a.PGPSignatureDate = time.Now().UTC() var jsonAction []byte if *pretty { jsonAction, err = json.MarshalIndent(a, "", "\t") } else { jsonAction, err = json.Marshal(a) } if err != nil { panic(err) } // if asked, url encode the action before marshaling it actionstr := string(jsonAction) if *urlencode { strJsonAction := string(jsonAction) actionstr = url.QueryEscape(strJsonAction) } if *posturl != "" { resp, err := http.PostForm(*posturl, url.Values{"action": {actionstr}}) if err != nil { panic(err) } var buf [512]byte reader := resp.Body for { n, err := reader.Read(buf[0:]) if err != nil { os.Exit(0) } fmt.Print(string(buf[0:n])) } } // find keyring in default location u, err := user.Current() if err != nil { panic(err) } // load keyring var gnupghome string gnupghome = os.Getenv("GNUPGHOME") if gnupghome == "" { gnupghome = "/.gnupg" } keyring, err := os.Open(u.HomeDir + gnupghome + "/pubring.gpg") if err != nil { panic(err) } defer keyring.Close() // syntax checking err = a.Validate() if err != nil { panic(err) } // syntax checking err = a.VerifySignature(keyring) if err != nil { panic(err) } }
// destroyAgent issues an `agentdestroy` action targetted to a specific agent // and updates the status of the agent in the database func destroyAgent(agent mig.Agent, ctx Context) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("destroyAgent() -> %v", e) } ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: "leaving destroyAgent()"}.Debug() }() // generate an `agentdestroy` action for this agent killAction := mig.Action{ ID: mig.GenID(), Name: fmt.Sprintf("Destroy agent %s", agent.Name), Target: agent.QueueLoc, ValidFrom: time.Now().Add(-60 * time.Second).UTC(), ExpireAfter: time.Now().Add(30 * time.Minute).UTC(), SyntaxVersion: 1, } var opparams struct { PID int `json:"pid"` Version string `json:"version"` } opparams.PID = agent.PID opparams.Version = agent.Version killOperation := mig.Operation{ Module: "agentdestroy", Parameters: opparams, } killAction.Operations = append(killAction.Operations, killOperation) // sign the action with the scheduler PGP key str, err := killAction.String() if err != nil { panic(err) } secringFile, err := os.Open(ctx.PGP.Home + "/secring.gpg") defer secringFile.Close() pgpsig, err := sign.Sign(str, ctx.PGP.KeyID, secringFile) if err != nil { panic(err) } killAction.PGPSignatures = append(killAction.PGPSignatures, pgpsig) var jsonAction []byte jsonAction, err = json.Marshal(killAction) if err != nil { panic(err) } // write the action to the spool for scheduling dest := fmt.Sprintf("%s/%.0f.json", ctx.Directories.Action.New, killAction.ID) err = safeWrite(ctx, dest, jsonAction) if err != nil { panic(err) } // mark the agent as `destroyed` in the database err = ctx.DB.MarkAgentDestroyed(agent) if err != nil { panic(err) } ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Requested destruction of agent '%s' with PID '%d'", agent.Name, agent.PID)}.Info() return }