func generateSerialRequestAssertion() (string, error) { privateKey, err := generatePrivateKey() if err != nil { return "", err } encodedPubKey, err := asserts.EncodePublicKey(privateKey.PublicKey()) if err != nil { return "", err } // Generate a request-id r, _ := getRequestID() headers := map[string]interface{}{ "brand-id": request.Brand, "device-key": string(encodedPubKey), "request-id": r, "model": request.Model, "serial": request.SerialNumber, } sreq, err := asserts.SignWithoutAuthority(asserts.SerialRequestType, headers, []byte(""), privateKey) if err != nil { return "", err } assertSR := asserts.Encode(sreq) return string(assertSR), nil }
func (dbs *databaseSuite) TestPublicKey(c *C) { pk := testPrivKey1 keyID := pk.PublicKey().ID() err := dbs.db.ImportKey(pk) c.Assert(err, IsNil) pubk, err := dbs.db.PublicKey(keyID) c.Assert(err, IsNil) c.Check(pubk.ID(), Equals, keyID) // usual pattern is to then encode it encoded, err := asserts.EncodePublicKey(pubk) c.Assert(err, IsNil) data, err := base64.StdEncoding.DecodeString(string(encoded)) c.Assert(err, IsNil) c.Check(data[0], Equals, uint8(1)) // v1 // check details of packet const newHeaderBits = 0x80 | 0x40 c.Check(data[1]&newHeaderBits, Equals, uint8(newHeaderBits)) c.Check(data[2] < 192, Equals, true) // small packet, 1 byte length c.Check(data[3], Equals, uint8(4)) // openpgp v4 pkt, err := packet.Read(bytes.NewBuffer(data[1:])) c.Assert(err, IsNil) pubKey, ok := pkt.(*packet.PublicKey) c.Assert(ok, Equals, true) c.Check(pubKey.PubKeyAlgo, Equals, packet.PubKeyAlgoRSA) c.Check(pubKey.IsSubkey, Equals, false) fixedTimestamp := time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC) c.Check(pubKey.CreationTime.Equal(fixedTimestamp), Equals, true) // hash of blob content == hash of key h384 := sha3.Sum384(data) encHash := base64.RawURLEncoding.EncodeToString(h384[:]) c.Check(encHash, DeepEquals, testPrivKey1SHA3_384) }
func (aks *accountKeySuite) TestAccountKeyCheckNameClash(c *C) { trustedKey := testPrivKey0 headers := map[string]interface{}{ "authority-id": "canonical", "account-id": "acc-id1", "name": "default", "public-key-sha3-384": aks.keyID, "since": aks.since.Format(time.RFC3339), "until": aks.until.Format(time.RFC3339), } accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) c.Assert(err, IsNil) db := aks.openDB(c) aks.prereqAccount(c, db) err = db.Add(accKey) c.Assert(err, IsNil) newPrivKey, _ := assertstest.GenerateKey(752) err = db.ImportKey(newPrivKey) c.Assert(err, IsNil) newPubKey, err := db.PublicKey(newPrivKey.PublicKey().ID()) c.Assert(err, IsNil) newPubKeyEncoded, err := asserts.EncodePublicKey(newPubKey) headers["public-key-sha3-384"] = newPubKey.ID() headers["revision"] = "1" newAccKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, newPubKeyEncoded, trustedKey) c.Assert(err, IsNil) err = db.Check(newAccKey) c.Assert(err, ErrorMatches, fmt.Sprintf(`account-key assertion for "acc-id1" with ID %q has the same name "default" as existing ID %q`, newPubKey.ID(), aks.keyID)) }
func (aks *accountKeySuite) TestAccountKeyCheckSameAccountAndDifferentName(c *C) { trustedKey := testPrivKey0 headers := map[string]interface{}{ "authority-id": "canonical", "account-id": "acc-id1", "name": "default", "public-key-sha3-384": aks.keyID, "since": aks.since.Format(time.RFC3339), "until": aks.until.Format(time.RFC3339), } accKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, []byte(aks.pubKeyBody), trustedKey) c.Assert(err, IsNil) db := aks.openDB(c) aks.prereqAccount(c, db) err = db.Add(accKey) c.Assert(err, IsNil) newPrivKey, _ := assertstest.GenerateKey(752) err = db.ImportKey(newPrivKey) c.Assert(err, IsNil) newPubKey, err := db.PublicKey(newPrivKey.PublicKey().ID()) c.Assert(err, IsNil) newPubKeyEncoded, err := asserts.EncodePublicKey(newPubKey) headers["name"] = "another" headers["public-key-sha3-384"] = newPubKey.ID() newAccKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, newPubKeyEncoded, trustedKey) c.Assert(err, IsNil) err = db.Check(newAccKey) c.Assert(err, IsNil) }
func (ss *serialSuite) SetUpSuite(c *C) { ss.ts = time.Now().Truncate(time.Second).UTC() ss.tsLine = "timestamp: " + ss.ts.Format(time.RFC3339) + "\n" ss.deviceKey = testPrivKey2 encodedPubKey, err := asserts.EncodePublicKey(ss.deviceKey.PublicKey()) c.Assert(err, IsNil) ss.encodedDevKey = string(encodedPubKey) }
func prepareSerialRequest(t *state.Task, privKey asserts.PrivateKey, device *auth.DeviceState, client *http.Client, cfg *serialRequestConfig) (string, error) { st := t.State() st.Unlock() defer st.Lock() req, err := http.NewRequest("POST", cfg.requestIDURL, nil) if err != nil { return "", fmt.Errorf("internal error: cannot create request-id request %q", cfg.requestIDURL) } cfg.applyHeaders(req) resp, err := client.Do(req) if err != nil { return "", retryErr(t, "cannot retrieve request-id for making a request for a serial: %v", err) } defer resp.Body.Close() if resp.StatusCode != 200 { return "", retryErr(t, "cannot retrieve request-id for making a request for a serial: unexpected status %d", resp.StatusCode) } dec := json.NewDecoder(resp.Body) var requestID requestIDResp err = dec.Decode(&requestID) if err != nil { // assume broken i/o return "", retryErr(t, "cannot read response with request-id for making a request for a serial: %v", err) } encodedPubKey, err := asserts.EncodePublicKey(privKey.PublicKey()) if err != nil { return "", fmt.Errorf("internal error: cannot encode device public key: %v", err) } headers := map[string]interface{}{ "brand-id": device.Brand, "model": device.Model, "request-id": requestID.RequestID, "device-key": string(encodedPubKey), } if cfg.proposedSerial != "" { headers["serial"] = cfg.proposedSerial } serialReq, err := asserts.SignWithoutAuthority(asserts.SerialRequestType, headers, cfg.body, privKey) if err != nil { return "", err } return string(asserts.Encode(serialReq)), nil }
func (s *deviceMgrSuite) TestDeviceAssertionsDeviceSessionRequest(c *C) { // nothing there _, _, err := s.mgr.DeviceSessionRequest("NONCE-1") c.Check(err, Equals, state.ErrNoState) // setup state as done by device initialisation s.state.Lock() devKey, _ := assertstest.GenerateKey(1024) encDevKey, err := asserts.EncodePublicKey(devKey.PublicKey()) c.Check(err, IsNil) seriala, err := s.storeSigning.Sign(asserts.SerialType, map[string]interface{}{ "brand-id": "canonical", "model": "pc", "serial": "8989", "device-key": string(encDevKey), "device-key-sha3-384": devKey.PublicKey().ID(), "timestamp": time.Now().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) err = assertstate.Add(s.state, seriala) c.Assert(err, IsNil) auth.SetDevice(s.state, &auth.DeviceState{ Brand: "canonical", Model: "pc", Serial: "8989", KeyID: devKey.PublicKey().ID(), }) s.mgr.KeypairManager().Put(devKey) s.state.Unlock() sessReq, serial, err := s.mgr.DeviceSessionRequest("NONCE-1") c.Assert(err, IsNil) c.Check(serial.Serial(), Equals, "8989") // correctly signed with device key err = asserts.SignatureCheck(sessReq, devKey.PublicKey()) c.Check(err, IsNil) c.Check(sessReq.BrandID(), Equals, "canonical") c.Check(sessReq.Model(), Equals, "pc") c.Check(sessReq.Serial(), Equals, "8989") c.Check(sessReq.Nonce(), Equals, "NONCE-1") }
func (x *cmdExportKey) Execute(args []string) error { if len(args) > 0 { return ErrExtraArgs } keyName := string(x.Positional.KeyName) if keyName == "" { keyName = "default" } manager := asserts.NewGPGKeypairManager() if x.Account != "" { privKey, err := manager.GetByName(keyName) if err != nil { return err } pubKey := privKey.PublicKey() headers := map[string]interface{}{ "account-id": x.Account, "name": keyName, "public-key-sha3-384": pubKey.ID(), "since": time.Now().UTC().Format(time.RFC3339), // XXX: To support revocation, we need to check for matching known assertions and set a suitable revision if we find one. } body, err := asserts.EncodePublicKey(pubKey) if err != nil { return err } assertion, err := asserts.SignWithoutAuthority(asserts.AccountKeyRequestType, headers, body, privKey) if err != nil { return err } fmt.Fprint(Stdout, string(asserts.Encode(assertion))) } else { encoded, err := manager.Export(keyName) if err != nil { return err } fmt.Fprintf(Stdout, "%s\n", encoded) } return nil }
func (aks *accountKeySuite) SetUpSuite(c *C) { cfg1 := &asserts.DatabaseConfig{} accDb, err := asserts.OpenDatabase(cfg1) c.Assert(err, IsNil) aks.privKey = testPrivKey1 err = accDb.ImportKey(aks.privKey) c.Assert(err, IsNil) aks.keyID = aks.privKey.PublicKey().ID() pubKey, err := accDb.PublicKey(aks.keyID) c.Assert(err, IsNil) pubKeyEncoded, err := asserts.EncodePublicKey(pubKey) c.Assert(err, IsNil) aks.pubKeyBody = string(pubKeyEncoded) aks.since, err = time.Parse(time.RFC822, "16 Nov 15 15:04 UTC") c.Assert(err, IsNil) aks.until = aks.since.AddDate(1, 0, 0) aks.sinceLine = "since: " + aks.since.Format(time.RFC3339) + "\n" aks.untilLine = "until: " + aks.until.Format(time.RFC3339) + "\n" }
func generateSerialRequestAssertion(model, serial string) (string, error) { privateKey, _ := generatePrivateKey() encodedPubKey, _ := asserts.EncodePublicKey(privateKey.PublicKey()) headers := map[string]interface{}{ "brand-id": "System", "device-key": string(encodedPubKey), "request-id": "REQID", "model": model, } body := fmt.Sprintf("serial: %s", serial) sreq, err := asserts.SignWithoutAuthority(asserts.SerialRequestType, headers, []byte(body), privateKey) if err != nil { return "", err } assertSR := asserts.Encode(sreq) return string(assertSR), nil }
// NewAccountKey creates an account-key assertion for the account, it fills in values for missing headers as needed. In panics on error. func NewAccountKey(db SignerDB, acct *asserts.Account, otherHeaders map[string]interface{}, pubKey asserts.PublicKey, keyID string) *asserts.AccountKey { if otherHeaders == nil { otherHeaders = make(map[string]interface{}) } otherHeaders["account-id"] = acct.AccountID() otherHeaders["public-key-sha3-384"] = pubKey.ID() if otherHeaders["name"] == nil { otherHeaders["name"] = "default" } if otherHeaders["since"] == nil { otherHeaders["since"] = time.Now().Format(time.RFC3339) } encodedPubKey, err := asserts.EncodePublicKey(pubKey) if err != nil { panic(err) } a, err := db.Sign(asserts.AccountKeyType, otherHeaders, encodedPubKey, keyID) if err != nil { panic(err) } return a.(*asserts.AccountKey) }
func (safs *signAddFindSuite) TestDontLetAddConfusinglyAssertionClashingWithTrustedOnes(c *C) { // trusted pubKey0, err := safs.signingDB.PublicKey(safs.signingKeyID) c.Assert(err, IsNil) pubKey0Encoded, err := asserts.EncodePublicKey(pubKey0) c.Assert(err, IsNil) now := time.Now().UTC() headers := map[string]interface{}{ "authority-id": "canonical", "account-id": "canonical", "public-key-sha3-384": safs.signingKeyID, "name": "default", "since": now.Format(time.RFC3339), "until": now.AddDate(1, 0, 0).Format(time.RFC3339), } tKey, err := safs.signingDB.Sign(asserts.AccountKeyType, headers, []byte(pubKey0Encoded), safs.signingKeyID) c.Assert(err, IsNil) err = safs.db.Add(tKey) c.Check(err, ErrorMatches, `cannot add "account-key" assertion with primary key clashing with a trusted assertion: .*`) }
func prepareSerialRequest(t *state.Task, privKey asserts.PrivateKey, device *auth.DeviceState, client *http.Client) (string, error) { st := t.State() st.Unlock() defer st.Lock() resp, err := client.Post(requestIDURL, "", nil) if err != nil { return "", retryErr(t, "cannot retrieve request-id for making a request for a serial: %v", err) } defer resp.Body.Close() if resp.StatusCode != 200 { return "", retryErr(t, "cannot retrieve request-id for making a request for a serial: unexpected status %d", resp.StatusCode) } dec := json.NewDecoder(resp.Body) var requestID requestIDResp err = dec.Decode(&requestID) if err != nil { // assume broken i/o return "", retryErr(t, "cannot read response with request-id for making a request for a serial: %v", err) } encodedPubKey, err := asserts.EncodePublicKey(privKey.PublicKey()) if err != nil { return "", fmt.Errorf("internal error: cannot encode device public key: %v", err) } serialReq, err := asserts.SignWithoutAuthority(asserts.SerialRequestType, map[string]interface{}{ "brand-id": device.Brand, "model": device.Model, "request-id": requestID.RequestID, "device-key": string(encodedPubKey), }, nil, privKey) // XXX: fill body with some agreed hardware details if err != nil { return "", err } return string(asserts.Encode(serialReq)), nil }
func (s *deviceMgrSuite) TestDeviceManagerEnsureSeedYamlRecover(c *C) { release.OnClassic = false restore := devicestate.MockPopulateStateFromSeed(func(*state.State) (ts []*state.TaskSet, err error) { return nil, errors.New("should not be called") }) defer restore() s.state.Lock() defer s.state.Unlock() s.setupCore(c, "ubuntu-core", ` name: ubuntu-core type: os version: ubuntu-core `, "") // have a model assertion model, err := s.storeSigning.Sign(asserts.ModelType, map[string]interface{}{ "series": "16", "brand-id": "canonical", "model": "pc", "gadget": "pc", "kernel": "kernel", "architecture": "amd64", "timestamp": time.Now().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) err = assertstate.Add(s.state, model) c.Assert(err, IsNil) // have a serial assertion devKey, _ := assertstest.GenerateKey(752) encDevKey, err := asserts.EncodePublicKey(devKey.PublicKey()) keyID := devKey.PublicKey().ID() c.Assert(err, IsNil) serial, err := s.storeSigning.Sign(asserts.SerialType, map[string]interface{}{ "brand-id": "canonical", "model": "pc", "serial": "8989", "device-key": string(encDevKey), "device-key-sha3-384": keyID, "timestamp": time.Now().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) err = assertstate.Add(s.state, serial) c.Assert(err, IsNil) // forgotten key id and serial auth.SetDevice(s.state, &auth.DeviceState{ Brand: "canonical", Model: "pc", }) // put key on disk err = s.mgr.KeypairManager().Put(devKey) c.Assert(err, IsNil) // extra unused stuff junk1 := filepath.Join(dirs.SnapDeviceDir, "private-keys-v1", "junkjunk1") err = ioutil.WriteFile(junk1, nil, 0644) c.Assert(err, IsNil) junk2 := filepath.Join(dirs.SnapDeviceDir, "private-keys-v1", "junkjunk2") err = ioutil.WriteFile(junk2, nil, 0644) c.Assert(err, IsNil) // double check pat := filepath.Join(dirs.SnapDeviceDir, "private-keys-v1", "*") onDisk, err := filepath.Glob(pat) c.Assert(err, IsNil) c.Check(onDisk, HasLen, 3) s.state.Unlock() err = s.mgr.EnsureSeedYaml() s.state.Lock() c.Assert(err, IsNil) c.Check(s.state.Changes(), HasLen, 0) var seeded bool err = s.state.Get("seeded", &seeded) c.Assert(err, IsNil) c.Check(seeded, Equals, true) device, err := auth.Device(s.state) c.Assert(err, IsNil) c.Check(device, DeepEquals, &auth.DeviceState{ Brand: "canonical", Model: "pc", KeyID: keyID, Serial: "8989", }) // key is still there _, err = s.mgr.KeypairManager().Get(keyID) c.Assert(err, IsNil) onDisk, err = filepath.Glob(pat) c.Assert(err, IsNil) // junk was removed c.Check(onDisk, HasLen, 1) }
func (s *deviceMgrSuite) TestDeviceAssertionsModelAndSerial(c *C) { // nothing in the state s.state.Lock() _, err := devicestate.Model(s.state) s.state.Unlock() c.Check(err, Equals, state.ErrNoState) s.state.Lock() _, err = devicestate.Serial(s.state) s.state.Unlock() c.Check(err, Equals, state.ErrNoState) _, err = s.mgr.Model() c.Check(err, Equals, state.ErrNoState) _, err = s.mgr.Serial() c.Check(err, Equals, state.ErrNoState) // just brand and model s.state.Lock() auth.SetDevice(s.state, &auth.DeviceState{ Brand: "canonical", Model: "pc", }) s.state.Unlock() _, err = s.mgr.Model() c.Check(err, Equals, state.ErrNoState) _, err = s.mgr.Serial() c.Check(err, Equals, state.ErrNoState) // have a model assertion model, err := s.storeSigning.Sign(asserts.ModelType, map[string]interface{}{ "series": "16", "brand-id": "canonical", "model": "pc", "gadget": "pc", "kernel": "kernel", "architecture": "amd64", "timestamp": time.Now().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) s.state.Lock() err = assertstate.Add(s.state, model) s.state.Unlock() c.Assert(err, IsNil) mod, err := s.mgr.Model() c.Assert(err, IsNil) c.Assert(mod.BrandID(), Equals, "canonical") s.state.Lock() mod, err = devicestate.Model(s.state) s.state.Unlock() c.Assert(err, IsNil) c.Assert(mod.BrandID(), Equals, "canonical") _, err = s.mgr.Serial() c.Check(err, Equals, state.ErrNoState) // have a serial as well s.state.Lock() auth.SetDevice(s.state, &auth.DeviceState{ Brand: "canonical", Model: "pc", Serial: "8989", }) s.state.Unlock() _, err = s.mgr.Model() c.Assert(err, IsNil) _, err = s.mgr.Serial() c.Check(err, Equals, state.ErrNoState) // have a serial assertion devKey, _ := assertstest.GenerateKey(752) encDevKey, err := asserts.EncodePublicKey(devKey.PublicKey()) c.Assert(err, IsNil) serial, err := s.storeSigning.Sign(asserts.SerialType, map[string]interface{}{ "brand-id": "canonical", "model": "pc", "serial": "8989", "device-key": string(encDevKey), "device-key-sha3-384": devKey.PublicKey().ID(), "timestamp": time.Now().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) s.state.Lock() err = assertstate.Add(s.state, serial) s.state.Unlock() c.Assert(err, IsNil) _, err = s.mgr.Model() c.Assert(err, IsNil) ser, err := s.mgr.Serial() c.Assert(err, IsNil) c.Check(ser.Serial(), Equals, "8989") s.state.Lock() ser, err = devicestate.Serial(s.state) s.state.Unlock() c.Assert(err, IsNil) c.Check(ser.Serial(), Equals, "8989") }
func (s *authContextSetupSuite) SetUpTest(c *C) { tempdir := c.MkDir() dirs.SetRootDir(tempdir) err := os.MkdirAll(filepath.Dir(dirs.SnapStateFile), 0755) c.Assert(err, IsNil) captureAuthContext := func(_ *store.Config, ac auth.AuthContext) *store.Store { s.ac = ac return nil } r := overlord.MockStoreNew(captureAuthContext) defer r() s.storeSigning = assertstest.NewStoreStack("can0nical", rootPrivKey, storePrivKey) s.restoreTrusted = sysdb.InjectTrusted(s.storeSigning.Trusted) s.brandSigning = assertstest.NewSigningDB("my-brand", brandPrivKey) brandAcct := assertstest.NewAccount(s.storeSigning, "my-brand", map[string]interface{}{ "account-id": "my-brand", "verification": "certified", }, "") s.storeSigning.Add(brandAcct) brandAccKey := assertstest.NewAccountKey(s.storeSigning, brandAcct, nil, brandPrivKey.PublicKey(), "") s.storeSigning.Add(brandAccKey) model, err := s.brandSigning.Sign(asserts.ModelType, map[string]interface{}{ "series": "16", "authority-id": "my-brand", "brand-id": "my-brand", "model": "my-model", "architecture": "amd64", "store": "my-brand-store-id", "gadget": "pc", "kernel": "pc-kernel", "timestamp": time.Now().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) s.model = model.(*asserts.Model) encDevKey, err := asserts.EncodePublicKey(deviceKey.PublicKey()) c.Assert(err, IsNil) serial, err := s.brandSigning.Sign(asserts.SerialType, map[string]interface{}{ "authority-id": "my-brand", "brand-id": "my-brand", "model": "my-model", "serial": "7878", "device-key": string(encDevKey), "device-key-sha3-384": deviceKey.PublicKey().ID(), "timestamp": time.Now().Format(time.RFC3339), }, nil, "") c.Assert(err, IsNil) s.serial = serial.(*asserts.Serial) o, err := overlord.New() c.Assert(err, IsNil) s.o = o st := o.State() st.Lock() defer st.Unlock() prereqs := []asserts.Assertion{s.storeSigning.StoreAccountKey(""), brandAcct, brandAccKey} for _, a := range prereqs { err = assertstate.Add(st, a) c.Assert(err, IsNil) } }