github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/overlord/devicestate/devicestate_serial_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2019 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package devicestate_test
    21  
    22  import (
    23  	"fmt"
    24  	"net"
    25  	"net/http"
    26  	"net/http/httptest"
    27  	"net/url"
    28  	"os"
    29  	"path/filepath"
    30  	"syscall"
    31  	"time"
    32  
    33  	. "gopkg.in/check.v1"
    34  	"gopkg.in/yaml.v2"
    35  
    36  	"github.com/snapcore/snapd/asserts"
    37  	"github.com/snapcore/snapd/asserts/assertstest"
    38  	"github.com/snapcore/snapd/asserts/sysdb"
    39  	"github.com/snapcore/snapd/dirs"
    40  	"github.com/snapcore/snapd/httputil"
    41  	"github.com/snapcore/snapd/logger"
    42  	"github.com/snapcore/snapd/osutil"
    43  	"github.com/snapcore/snapd/overlord/assertstate"
    44  	"github.com/snapcore/snapd/overlord/assertstate/assertstatetest"
    45  	"github.com/snapcore/snapd/overlord/auth"
    46  	"github.com/snapcore/snapd/overlord/configstate/config"
    47  	"github.com/snapcore/snapd/overlord/devicestate"
    48  	"github.com/snapcore/snapd/overlord/devicestate/devicestatetest"
    49  	"github.com/snapcore/snapd/overlord/snapstate"
    50  	"github.com/snapcore/snapd/overlord/state"
    51  	"github.com/snapcore/snapd/overlord/storecontext"
    52  	"github.com/snapcore/snapd/release"
    53  	"github.com/snapcore/snapd/snap"
    54  	"github.com/snapcore/snapd/snap/snaptest"
    55  	"github.com/snapcore/snapd/snapdenv"
    56  	"github.com/snapcore/snapd/strutil"
    57  	"github.com/snapcore/snapd/testutil"
    58  )
    59  
    60  var testKeyLength = 1024
    61  
    62  type deviceMgrSerialSuite struct {
    63  	deviceMgrBaseSuite
    64  }
    65  
    66  var _ = Suite(&deviceMgrSerialSuite{})
    67  
    68  func (s *deviceMgrSerialSuite) signSerial(c *C, bhv *devicestatetest.DeviceServiceBehavior, headers map[string]interface{}, body []byte) (serial asserts.Assertion, ancillary []asserts.Assertion, err error) {
    69  	brandID := headers["brand-id"].(string)
    70  	model := headers["model"].(string)
    71  	keyID := ""
    72  
    73  	var signing assertstest.SignerDB = s.storeSigning
    74  
    75  	switch model {
    76  	case "pc", "pc2", "pc-20":
    77  		fallthrough
    78  	case "classic-alt-store":
    79  		c.Check(brandID, Equals, "canonical")
    80  	case "my-model-accept-generic":
    81  		c.Check(brandID, Equals, "my-brand")
    82  		headers["authority-id"] = "generic"
    83  		keyID = s.storeSigning.GenericKey.PublicKeyID()
    84  	case "generic-classic":
    85  		c.Check(brandID, Equals, "generic")
    86  		headers["authority-id"] = "generic"
    87  		keyID = s.storeSigning.GenericKey.PublicKeyID()
    88  	case "rereg-model":
    89  		headers["authority-id"] = "rereg-brand"
    90  		signing = s.brands.Signing("rereg-brand")
    91  	default:
    92  		return nil, nil, fmt.Errorf("unknown model: %s", model)
    93  	}
    94  	a, err := signing.Sign(asserts.SerialType, headers, body, keyID)
    95  	return a, s.ancillary, err
    96  }
    97  
    98  func (s *deviceMgrSerialSuite) mockServer(c *C, reqID string, bhv *devicestatetest.DeviceServiceBehavior) *httptest.Server {
    99  	if bhv == nil {
   100  		bhv = &devicestatetest.DeviceServiceBehavior{}
   101  	}
   102  
   103  	bhv.ReqID = reqID
   104  	bhv.SignSerial = s.signSerial
   105  	bhv.ExpectedCapabilities = "serial-stream"
   106  
   107  	return devicestatetest.MockDeviceService(c, bhv)
   108  }
   109  
   110  func (s *deviceMgrSerialSuite) findBecomeOperationalChange(skipIDs ...string) *state.Change {
   111  	for _, chg := range s.state.Changes() {
   112  		if chg.Kind() == "become-operational" && !strutil.ListContains(skipIDs, chg.ID()) {
   113  			return chg
   114  		}
   115  	}
   116  	return nil
   117  }
   118  
   119  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappy(c *C) {
   120  	r1 := devicestate.MockKeyLength(testKeyLength)
   121  	defer r1()
   122  
   123  	mockServer := s.mockServer(c, "REQID-1", nil)
   124  	defer mockServer.Close()
   125  
   126  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
   127  	defer r2()
   128  
   129  	// setup state as will be done by first-boot
   130  	s.state.Lock()
   131  	defer s.state.Unlock()
   132  
   133  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   134  		"architecture": "amd64",
   135  		"kernel":       "pc-kernel",
   136  		"gadget":       "pc",
   137  	})
   138  
   139  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   140  		Brand: "canonical",
   141  		Model: "pc",
   142  	})
   143  
   144  	// avoid full seeding
   145  	s.seeding()
   146  
   147  	// not started if not seeded
   148  	s.state.Unlock()
   149  	s.se.Ensure()
   150  	s.state.Lock()
   151  
   152  	becomeOperational := s.findBecomeOperationalChange()
   153  	c.Check(becomeOperational, IsNil)
   154  
   155  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
   156  	// mark it as seeded
   157  	s.state.Set("seeded", true)
   158  
   159  	// runs the whole device registration process
   160  	s.state.Unlock()
   161  	s.settle(c)
   162  	s.state.Lock()
   163  
   164  	becomeOperational = s.findBecomeOperationalChange()
   165  	c.Assert(becomeOperational, NotNil)
   166  
   167  	c.Check(becomeOperational.Status().Ready(), Equals, true)
   168  	c.Check(becomeOperational.Err(), IsNil)
   169  
   170  	device, err := devicestatetest.Device(s.state)
   171  	c.Assert(err, IsNil)
   172  	c.Check(device.Brand, Equals, "canonical")
   173  	c.Check(device.Model, Equals, "pc")
   174  	c.Check(device.Serial, Equals, "9999")
   175  
   176  	ok := false
   177  	select {
   178  	case <-s.mgr.Registered():
   179  		ok = true
   180  	case <-time.After(5 * time.Second):
   181  		c.Fatal("should have been marked registered")
   182  	}
   183  	c.Check(ok, Equals, true)
   184  
   185  	a, err := s.db.Find(asserts.SerialType, map[string]string{
   186  		"brand-id": "canonical",
   187  		"model":    "pc",
   188  		"serial":   "9999",
   189  	})
   190  	c.Assert(err, IsNil)
   191  	serial := a.(*asserts.Serial)
   192  
   193  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
   194  	c.Assert(err, IsNil)
   195  	c.Check(privKey, NotNil)
   196  
   197  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
   198  
   199  	// check that keypair manager is under device
   200  	c.Check(osutil.IsDirectory(filepath.Join(dirs.SnapDeviceDir, "private-keys-v1")), Equals, true)
   201  }
   202  
   203  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyWithProxy(c *C) {
   204  	r1 := devicestate.MockKeyLength(testKeyLength)
   205  	defer r1()
   206  
   207  	mockServer := s.mockServer(c, "REQID-1", nil)
   208  	defer mockServer.Close()
   209  
   210  	// as core.proxy.store is set, should not need to do this but just in case
   211  	r2 := devicestate.MockBaseStoreURL(mockServer.URL + "/direct/baaad/")
   212  	defer r2()
   213  
   214  	// setup state as will be done by first-boot
   215  	s.state.Lock()
   216  	defer s.state.Unlock()
   217  
   218  	tr := config.NewTransaction(s.state)
   219  	c.Assert(tr.Set("core", "proxy.store", "foo"), IsNil)
   220  	tr.Commit()
   221  	operatorAcct := assertstest.NewAccount(s.storeSigning, "foo-operator", nil, "")
   222  
   223  	// have a store assertion.
   224  	stoAs, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{
   225  		"store":       "foo",
   226  		"url":         mockServer.URL,
   227  		"operator-id": operatorAcct.AccountID(),
   228  		"timestamp":   time.Now().Format(time.RFC3339),
   229  	}, nil, "")
   230  	c.Assert(err, IsNil)
   231  
   232  	assertstatetest.AddMany(s.state, operatorAcct, stoAs)
   233  
   234  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   235  		"architecture": "amd64",
   236  		"kernel":       "pc-kernel",
   237  		"gadget":       "pc",
   238  	})
   239  
   240  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   241  		Brand: "canonical",
   242  		Model: "pc",
   243  	})
   244  
   245  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
   246  	// mark as seeded
   247  	s.state.Set("seeded", true)
   248  
   249  	// runs the whole device registration process
   250  	s.state.Unlock()
   251  	s.settle(c)
   252  	s.state.Lock()
   253  
   254  	becomeOperational := s.findBecomeOperationalChange()
   255  	c.Assert(becomeOperational, NotNil)
   256  
   257  	c.Check(becomeOperational.Status().Ready(), Equals, true)
   258  	c.Check(becomeOperational.Err(), IsNil)
   259  
   260  	device, err := devicestatetest.Device(s.state)
   261  	c.Assert(err, IsNil)
   262  	c.Check(device.Brand, Equals, "canonical")
   263  	c.Check(device.Model, Equals, "pc")
   264  	c.Check(device.Serial, Equals, "9999")
   265  
   266  	ok := false
   267  	select {
   268  	case <-s.mgr.Registered():
   269  		ok = true
   270  	case <-time.After(5 * time.Second):
   271  		c.Fatal("should have been marked registered")
   272  	}
   273  	c.Check(ok, Equals, true)
   274  
   275  	a, err := s.db.Find(asserts.SerialType, map[string]string{
   276  		"brand-id": "canonical",
   277  		"model":    "pc",
   278  		"serial":   "9999",
   279  	})
   280  	c.Assert(err, IsNil)
   281  	serial := a.(*asserts.Serial)
   282  
   283  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
   284  	c.Assert(err, IsNil)
   285  	c.Check(privKey, NotNil)
   286  
   287  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
   288  }
   289  
   290  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyClassicNoGadget(c *C) {
   291  	restore := release.MockOnClassic(true)
   292  	defer restore()
   293  
   294  	r1 := devicestate.MockKeyLength(testKeyLength)
   295  	defer r1()
   296  
   297  	mockServer := s.mockServer(c, "REQID-1", nil)
   298  	defer mockServer.Close()
   299  
   300  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
   301  	defer r2()
   302  
   303  	// setup state as will be done by first-boot
   304  	s.state.Lock()
   305  	defer s.state.Unlock()
   306  
   307  	s.makeModelAssertionInState(c, "canonical", "classic-alt-store", map[string]interface{}{
   308  		"classic": "true",
   309  		"store":   "alt-store",
   310  	})
   311  
   312  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   313  		Brand: "canonical",
   314  		Model: "classic-alt-store",
   315  	})
   316  
   317  	// avoid full seeding
   318  	s.seeding()
   319  
   320  	// runs the whole device registration process
   321  	s.state.Unlock()
   322  	s.settle(c)
   323  	s.state.Lock()
   324  
   325  	becomeOperational := s.findBecomeOperationalChange()
   326  	c.Assert(becomeOperational, NotNil)
   327  
   328  	c.Check(becomeOperational.Status().Ready(), Equals, true)
   329  	c.Check(becomeOperational.Err(), IsNil)
   330  
   331  	device, err := devicestatetest.Device(s.state)
   332  	c.Assert(err, IsNil)
   333  	c.Check(device.Brand, Equals, "canonical")
   334  	c.Check(device.Model, Equals, "classic-alt-store")
   335  	c.Check(device.Serial, Equals, "9999")
   336  
   337  	a, err := s.db.Find(asserts.SerialType, map[string]string{
   338  		"brand-id": "canonical",
   339  		"model":    "classic-alt-store",
   340  		"serial":   "9999",
   341  	})
   342  	c.Assert(err, IsNil)
   343  	serial := a.(*asserts.Serial)
   344  
   345  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
   346  	c.Assert(err, IsNil)
   347  	c.Check(privKey, NotNil)
   348  
   349  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
   350  }
   351  
   352  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyClassicFallback(c *C) {
   353  	restore := release.MockOnClassic(true)
   354  	defer restore()
   355  
   356  	r1 := devicestate.MockKeyLength(testKeyLength)
   357  	defer r1()
   358  
   359  	mockServer := s.mockServer(c, "REQID-1", nil)
   360  	defer mockServer.Close()
   361  
   362  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
   363  	defer r2()
   364  
   365  	// setup state as will be done by first-boot
   366  	s.state.Lock()
   367  	defer s.state.Unlock()
   368  
   369  	// in this case is just marked seeded without snaps
   370  	s.state.Set("seeded", true)
   371  
   372  	// not started without some installation happening or happened
   373  	s.state.Unlock()
   374  	s.se.Ensure()
   375  	s.state.Lock()
   376  
   377  	becomeOperational := s.findBecomeOperationalChange()
   378  	c.Check(becomeOperational, IsNil)
   379  
   380  	// have a in-progress installation
   381  	inst := s.state.NewChange("install", "...")
   382  	task := s.state.NewTask("mount-snap", "...")
   383  	inst.AddTask(task)
   384  
   385  	// runs the whole device registration process
   386  	s.state.Unlock()
   387  	s.settle(c)
   388  	s.state.Lock()
   389  
   390  	becomeOperational = s.findBecomeOperationalChange()
   391  	c.Assert(becomeOperational, NotNil)
   392  
   393  	c.Check(becomeOperational.Status().Ready(), Equals, true)
   394  	c.Check(becomeOperational.Err(), IsNil)
   395  
   396  	device, err := devicestatetest.Device(s.state)
   397  	c.Assert(err, IsNil)
   398  	c.Check(device.Brand, Equals, "generic")
   399  	c.Check(device.Model, Equals, "generic-classic")
   400  	c.Check(device.Serial, Equals, "9999")
   401  
   402  	// model was installed
   403  	_, err = s.db.Find(asserts.ModelType, map[string]string{
   404  		"series":   "16",
   405  		"brand-id": "generic",
   406  		"model":    "generic-classic",
   407  		"classic":  "true",
   408  	})
   409  	c.Assert(err, IsNil)
   410  
   411  	a, err := s.db.Find(asserts.SerialType, map[string]string{
   412  		"brand-id": "generic",
   413  		"model":    "generic-classic",
   414  		"serial":   "9999",
   415  	})
   416  	c.Assert(err, IsNil)
   417  	serial := a.(*asserts.Serial)
   418  
   419  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
   420  	c.Assert(err, IsNil)
   421  	c.Check(privKey, NotNil)
   422  
   423  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
   424  
   425  	// auto-refreshes are possible
   426  	ok, err := devicestate.CanAutoRefresh(s.state)
   427  	c.Assert(err, IsNil)
   428  	c.Check(ok, Equals, true)
   429  }
   430  
   431  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationMyBrandAcceptGenericHappy(c *C) {
   432  	r1 := devicestate.MockKeyLength(testKeyLength)
   433  	defer r1()
   434  
   435  	mockServer := s.mockServer(c, "REQID-1", nil)
   436  	defer mockServer.Close()
   437  
   438  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
   439  	defer r2()
   440  
   441  	// setup state as will be done by first-boot
   442  	s.state.Lock()
   443  	defer s.state.Unlock()
   444  
   445  	s.makeModelAssertionInState(c, "my-brand", "my-model-accept-generic", map[string]interface{}{
   446  		"classic": "true",
   447  		"store":   "alt-store",
   448  		// accept generic as well to sign serials for this
   449  		"serial-authority": []interface{}{"generic"},
   450  	})
   451  
   452  	devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil)
   453  
   454  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   455  		Brand: "my-brand",
   456  		Model: "my-model-accept-generic",
   457  	})
   458  
   459  	// avoid full seeding
   460  	s.seeding()
   461  
   462  	// runs the whole device registration process
   463  	s.state.Unlock()
   464  	s.settle(c)
   465  	s.state.Lock()
   466  
   467  	becomeOperational := s.findBecomeOperationalChange()
   468  	c.Assert(becomeOperational, NotNil)
   469  
   470  	c.Check(becomeOperational.Status().Ready(), Equals, true)
   471  	c.Check(becomeOperational.Err(), IsNil)
   472  
   473  	device, err := devicestatetest.Device(s.state)
   474  	c.Assert(err, IsNil)
   475  	c.Check(device.Brand, Equals, "my-brand")
   476  	c.Check(device.Model, Equals, "my-model-accept-generic")
   477  	c.Check(device.Serial, Equals, "9999")
   478  
   479  	a, err := s.db.Find(asserts.SerialType, map[string]string{
   480  		"brand-id": "my-brand",
   481  		"model":    "my-model-accept-generic",
   482  		"serial":   "9999",
   483  	})
   484  	c.Assert(err, IsNil)
   485  	serial := a.(*asserts.Serial)
   486  	c.Check(serial.AuthorityID(), Equals, "generic")
   487  
   488  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
   489  	c.Assert(err, IsNil)
   490  	c.Check(privKey, NotNil)
   491  
   492  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
   493  }
   494  
   495  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationMyBrandMismatchedAuthority(c *C) {
   496  	r1 := devicestate.MockKeyLength(testKeyLength)
   497  	defer r1()
   498  
   499  	mockServer := s.mockServer(c, "REQID-1", nil)
   500  	defer mockServer.Close()
   501  
   502  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
   503  	defer r2()
   504  
   505  	// setup state as will be done by first-boot
   506  	s.state.Lock()
   507  	defer s.state.Unlock()
   508  
   509  	s.makeModelAssertionInState(c, "my-brand", "my-model-accept-generic", map[string]interface{}{
   510  		"classic": "true",
   511  		"store":   "alt-store",
   512  		// no serial-authority set
   513  	})
   514  
   515  	devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil)
   516  
   517  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   518  		Brand: "my-brand",
   519  		Model: "my-model-accept-generic",
   520  	})
   521  
   522  	// avoid full seeding
   523  	s.seeding()
   524  
   525  	// runs the whole device registration process
   526  	s.state.Unlock()
   527  	s.settle(c)
   528  	s.state.Lock()
   529  
   530  	becomeOperational := s.findBecomeOperationalChange()
   531  	c.Assert(becomeOperational, NotNil)
   532  
   533  	c.Check(becomeOperational.Status().Ready(), Equals, true)
   534  	c.Check(becomeOperational.Err(), ErrorMatches, `(?s).*obtained serial assertion is signed by authority "generic" different from brand "my-brand" without model assertion with serial-authority set to to allow for them.*`)
   535  }
   536  
   537  func (s *deviceMgrSerialSuite) TestDoRequestSerialIdempotentAfterAddSerial(c *C) {
   538  	privKey, _ := assertstest.GenerateKey(testKeyLength)
   539  
   540  	mockServer := s.mockServer(c, "REQID-1", nil)
   541  	defer mockServer.Close()
   542  
   543  	restore := devicestate.MockBaseStoreURL(mockServer.URL)
   544  	defer restore()
   545  
   546  	restore = devicestate.MockRepeatRequestSerial("after-add-serial")
   547  	defer restore()
   548  
   549  	// setup state as done by first-boot/Ensure/doGenerateDeviceKey
   550  	s.state.Lock()
   551  	defer s.state.Unlock()
   552  
   553  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   554  		"architecture": "amd64",
   555  		"kernel":       "pc-kernel",
   556  		"gadget":       "pc",
   557  	})
   558  
   559  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
   560  
   561  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   562  		Brand: "canonical",
   563  		Model: "pc",
   564  		KeyID: privKey.PublicKey().ID(),
   565  	})
   566  	devicestate.KeypairManager(s.mgr).Put(privKey)
   567  
   568  	t := s.state.NewTask("request-serial", "test")
   569  	chg := s.state.NewChange("become-operational", "...")
   570  	chg.AddTask(t)
   571  
   572  	// avoid full seeding
   573  	s.seeding()
   574  
   575  	s.state.Unlock()
   576  	s.se.Ensure()
   577  	s.se.Wait()
   578  	s.state.Lock()
   579  
   580  	c.Check(chg.Status(), Equals, state.DoingStatus)
   581  	c.Check(chg.Err(), IsNil)
   582  	device, err := devicestatetest.Device(s.state)
   583  	c.Check(err, IsNil)
   584  	_, err = s.db.Find(asserts.SerialType, map[string]string{
   585  		"brand-id": "canonical",
   586  		"model":    "pc",
   587  		"serial":   "9999",
   588  	})
   589  	c.Assert(err, IsNil)
   590  
   591  	ok := false
   592  	select {
   593  	case <-s.mgr.Registered():
   594  	default:
   595  		ok = true
   596  	}
   597  	c.Check(ok, Equals, true)
   598  
   599  	s.state.Unlock()
   600  	s.se.Ensure()
   601  	s.se.Wait()
   602  	s.state.Lock()
   603  
   604  	// Repeated handler run but set original serial.
   605  	c.Check(chg.Status(), Equals, state.DoneStatus)
   606  	device, err = devicestatetest.Device(s.state)
   607  	c.Check(err, IsNil)
   608  	c.Check(device.Serial, Equals, "9999")
   609  
   610  	ok = false
   611  	select {
   612  	case <-s.mgr.Registered():
   613  		ok = true
   614  	case <-time.After(5 * time.Second):
   615  		c.Fatal("should have been marked registered")
   616  	}
   617  	c.Check(ok, Equals, true)
   618  }
   619  
   620  func (s *deviceMgrSerialSuite) TestDoRequestSerialIdempotentAfterGotSerial(c *C) {
   621  	privKey, _ := assertstest.GenerateKey(testKeyLength)
   622  
   623  	mockServer := s.mockServer(c, "REQID-1", nil)
   624  	defer mockServer.Close()
   625  
   626  	restore := devicestate.MockBaseStoreURL(mockServer.URL)
   627  	defer restore()
   628  
   629  	restore = devicestate.MockRepeatRequestSerial("after-got-serial")
   630  	defer restore()
   631  
   632  	// setup state as done by first-boot/Ensure/doGenerateDeviceKey
   633  	s.state.Lock()
   634  	defer s.state.Unlock()
   635  
   636  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   637  		"architecture": "amd64",
   638  		"kernel":       "pc-kernel",
   639  		"gadget":       "pc",
   640  	})
   641  
   642  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
   643  
   644  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   645  		Brand: "canonical",
   646  		Model: "pc",
   647  		KeyID: privKey.PublicKey().ID(),
   648  	})
   649  	devicestate.KeypairManager(s.mgr).Put(privKey)
   650  
   651  	t := s.state.NewTask("request-serial", "test")
   652  	chg := s.state.NewChange("become-operational", "...")
   653  	chg.AddTask(t)
   654  
   655  	// avoid full seeding
   656  	s.seeding()
   657  
   658  	s.state.Unlock()
   659  	s.se.Ensure()
   660  	s.se.Wait()
   661  	s.state.Lock()
   662  
   663  	c.Check(chg.Status(), Equals, state.DoingStatus)
   664  	_, err := devicestatetest.Device(s.state)
   665  	c.Check(err, IsNil)
   666  	_, err = s.db.Find(asserts.SerialType, map[string]string{
   667  		"brand-id": "canonical",
   668  		"model":    "pc",
   669  		"serial":   "9999",
   670  	})
   671  	c.Assert(asserts.IsNotFound(err), Equals, true)
   672  
   673  	s.state.Unlock()
   674  	s.se.Ensure()
   675  	s.se.Wait()
   676  	s.state.Lock()
   677  
   678  	// Repeated handler run but set original serial.
   679  	c.Check(chg.Status(), Equals, state.DoneStatus)
   680  	c.Check(chg.Err(), IsNil)
   681  	device, err := devicestatetest.Device(s.state)
   682  	c.Check(err, IsNil)
   683  	c.Check(device.Serial, Equals, "9999")
   684  }
   685  
   686  func (s *deviceMgrSerialSuite) TestDoRequestSerialErrorsOnNoHost(c *C) {
   687  	if os.Getenv("http_proxy") != "" {
   688  		c.Skip("cannot run test when http proxy is in use, the error pattern is different")
   689  	}
   690  
   691  	const nonexistent_host = "nowhere.nowhere.test"
   692  
   693  	// check internet access
   694  	_, err := net.LookupHost(nonexistent_host)
   695  	if netErr, ok := err.(net.Error); !ok || netErr.Temporary() {
   696  		c.Skip("cannot run test with no internet access, the error pattern is different")
   697  	}
   698  
   699  	privKey, _ := assertstest.GenerateKey(testKeyLength)
   700  
   701  	nowhere := "http://" + nonexistent_host
   702  
   703  	restore := devicestate.MockBaseStoreURL(nowhere)
   704  	defer restore()
   705  
   706  	// setup state as done by first-boot/Ensure/doGenerateDeviceKey
   707  	s.state.Lock()
   708  	defer s.state.Unlock()
   709  
   710  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   711  		"architecture": "amd64",
   712  		"kernel":       "pc-kernel",
   713  		"gadget":       "pc",
   714  	})
   715  
   716  	devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil)
   717  
   718  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   719  		Brand: "canonical",
   720  		Model: "pc",
   721  		KeyID: privKey.PublicKey().ID(),
   722  	})
   723  	devicestate.KeypairManager(s.mgr).Put(privKey)
   724  
   725  	t := s.state.NewTask("request-serial", "test")
   726  	chg := s.state.NewChange("become-operational", "...")
   727  	chg.AddTask(t)
   728  
   729  	// avoid full seeding
   730  	s.seeding()
   731  
   732  	s.state.Unlock()
   733  	s.se.Ensure()
   734  	s.se.Wait()
   735  	s.state.Lock()
   736  
   737  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   738  }
   739  
   740  func (s *deviceMgrSerialSuite) TestDoRequestSerialMaxTentatives(c *C) {
   741  	privKey, _ := assertstest.GenerateKey(testKeyLength)
   742  
   743  	// immediate
   744  	r := devicestate.MockRetryInterval(0)
   745  	defer r()
   746  
   747  	r = devicestate.MockMaxTentatives(2)
   748  	defer r()
   749  
   750  	// this will trigger a reply 501 in the mock server
   751  	mockServer := s.mockServer(c, devicestatetest.ReqIDFailID501, nil)
   752  	defer mockServer.Close()
   753  
   754  	restore := devicestate.MockBaseStoreURL(mockServer.URL)
   755  	defer restore()
   756  
   757  	restore = devicestate.MockRepeatRequestSerial("after-add-serial")
   758  	defer restore()
   759  
   760  	// setup state as done by first-boot/Ensure/doGenerateDeviceKey
   761  	s.state.Lock()
   762  	defer s.state.Unlock()
   763  
   764  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   765  		"architecture": "amd64",
   766  		"kernel":       "pc-kernel",
   767  		"gadget":       "pc",
   768  	})
   769  
   770  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
   771  
   772  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   773  		Brand: "canonical",
   774  		Model: "pc",
   775  		KeyID: privKey.PublicKey().ID(),
   776  	})
   777  	devicestate.KeypairManager(s.mgr).Put(privKey)
   778  
   779  	t := s.state.NewTask("request-serial", "test")
   780  	chg := s.state.NewChange("become-operational", "...")
   781  	chg.AddTask(t)
   782  
   783  	// avoid full seeding
   784  	s.seeding()
   785  
   786  	s.state.Unlock()
   787  	s.se.Ensure()
   788  	s.se.Wait()
   789  	s.state.Lock()
   790  
   791  	c.Check(chg.Status(), Equals, state.DoingStatus)
   792  
   793  	s.state.Unlock()
   794  	s.se.Ensure()
   795  	s.se.Wait()
   796  	s.state.Lock()
   797  
   798  	c.Check(chg.Status(), Equals, state.ErrorStatus)
   799  	c.Check(chg.Err(), ErrorMatches, `(?s).*cannot retrieve request-id for making a request for a serial: unexpected status 501.*`)
   800  }
   801  
   802  type simulateNoNetRoundTripper struct{}
   803  
   804  func (s *simulateNoNetRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {
   805  	return nil, &net.OpError{
   806  		Op:   "dial",
   807  		Net:  "tcp",
   808  		Addr: &net.TCPAddr{IP: net.IPv4(10, 0, 0, 2), Port: 80},
   809  		Err: &os.SyscallError{
   810  			Syscall: "connect",
   811  			Err:     syscall.ENETUNREACH,
   812  		},
   813  	}
   814  }
   815  
   816  func (s *deviceMgrSerialSuite) TestDoRequestSerialNoNetwork(c *C) {
   817  	s.testDoRequestSerialKeepsRetrying(c, &simulateNoNetRoundTripper{})
   818  }
   819  
   820  type simulateNoDNSRoundTripper struct{}
   821  
   822  func (s *simulateNoDNSRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {
   823  	return nil, &net.OpError{
   824  		Op:  "dial",
   825  		Net: "tcp",
   826  		Err: &net.DNSError{
   827  			Err:         "Temporary failure in name resolution",
   828  			Name:        "www.ubuntu.com",
   829  			Server:      "",
   830  			IsTemporary: true,
   831  		},
   832  	}
   833  }
   834  
   835  func (s *deviceMgrSerialSuite) TestDoRequestSerialNoReachableDNS(c *C) {
   836  	s.testDoRequestSerialKeepsRetrying(c, &simulateNoDNSRoundTripper{})
   837  }
   838  
   839  func (s *deviceMgrSerialSuite) testDoRequestSerialKeepsRetrying(c *C, rt http.RoundTripper) {
   840  	privKey, _ := assertstest.GenerateKey(testKeyLength)
   841  
   842  	// immediate
   843  	r := devicestate.MockRetryInterval(0)
   844  	defer r()
   845  
   846  	// set a low maxRetry value
   847  	r = devicestate.MockMaxTentatives(3)
   848  	defer r()
   849  
   850  	mockServer := s.mockServer(c, "REQID-1", nil)
   851  	defer mockServer.Close()
   852  
   853  	restore := devicestate.MockBaseStoreURL(mockServer.URL)
   854  	defer restore()
   855  
   856  	restore = devicestate.MockRepeatRequestSerial("after-add-serial")
   857  	defer restore()
   858  
   859  	restore = devicestate.MockHttputilNewHTTPClient(func(opts *httputil.ClientOptions) *http.Client {
   860  		c.Check(opts.ProxyConnectHeader, NotNil)
   861  		return &http.Client{Transport: rt}
   862  	})
   863  	defer restore()
   864  
   865  	// setup state as done by first-boot/Ensure/doGenerateDeviceKey
   866  	s.state.Lock()
   867  	defer s.state.Unlock()
   868  
   869  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   870  		"architecture": "amd64",
   871  		"kernel":       "pc-kernel",
   872  		"gadget":       "pc",
   873  	})
   874  
   875  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
   876  
   877  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   878  		Brand: "canonical",
   879  		Model: "pc",
   880  		KeyID: privKey.PublicKey().ID(),
   881  	})
   882  	devicestate.KeypairManager(s.mgr).Put(privKey)
   883  
   884  	t := s.state.NewTask("request-serial", "test")
   885  	chg := s.state.NewChange("become-operational", "...")
   886  	chg.AddTask(t)
   887  
   888  	// avoid full seeding
   889  	s.seeding()
   890  
   891  	// ensure we keep trying even if we are well above maxTentative
   892  	for i := 0; i < 10; i++ {
   893  		s.state.Unlock()
   894  		s.se.Ensure()
   895  		s.se.Wait()
   896  		s.state.Lock()
   897  
   898  		c.Check(chg.Status(), Equals, state.DoingStatus)
   899  		c.Check(chg.Err(), IsNil)
   900  	}
   901  
   902  	c.Check(chg.Status(), Equals, state.DoingStatus)
   903  
   904  	var nTentatives int
   905  	err := t.Get("pre-poll-tentatives", &nTentatives)
   906  	c.Assert(err, IsNil)
   907  	c.Check(nTentatives, Equals, 0)
   908  }
   909  
   910  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationPollHappy(c *C) {
   911  	r1 := devicestate.MockKeyLength(testKeyLength)
   912  	defer r1()
   913  
   914  	mockServer := s.mockServer(c, devicestatetest.ReqIDPoll, nil)
   915  	defer mockServer.Close()
   916  
   917  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
   918  	defer r2()
   919  
   920  	// immediately
   921  	r3 := devicestate.MockRetryInterval(0)
   922  	defer r3()
   923  
   924  	// setup state as will be done by first-boot
   925  	s.state.Lock()
   926  	defer s.state.Unlock()
   927  
   928  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
   929  		"architecture": "amd64",
   930  		"kernel":       "pc-kernel",
   931  		"gadget":       "pc",
   932  	})
   933  
   934  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
   935  		Brand: "canonical",
   936  		Model: "pc",
   937  	})
   938  
   939  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
   940  	// mark as seeded
   941  	s.state.Set("seeded", true)
   942  
   943  	// runs the whole device registration process with polling
   944  	s.state.Unlock()
   945  	s.settle(c)
   946  	s.state.Lock()
   947  
   948  	becomeOperational := s.findBecomeOperationalChange()
   949  	c.Assert(becomeOperational, NotNil)
   950  
   951  	// needs 3 more Retry passes of polling
   952  	for i := 0; i < 3; i++ {
   953  		s.state.Unlock()
   954  		s.settle(c)
   955  		s.state.Lock()
   956  	}
   957  
   958  	c.Check(becomeOperational.Status().Ready(), Equals, true)
   959  	c.Check(becomeOperational.Err(), IsNil)
   960  
   961  	device, err := devicestatetest.Device(s.state)
   962  	c.Assert(err, IsNil)
   963  	c.Check(device.Brand, Equals, "canonical")
   964  	c.Check(device.Model, Equals, "pc")
   965  	c.Check(device.Serial, Equals, "10002")
   966  
   967  	a, err := s.db.Find(asserts.SerialType, map[string]string{
   968  		"brand-id": "canonical",
   969  		"model":    "pc",
   970  		"serial":   "10002",
   971  	})
   972  	c.Assert(err, IsNil)
   973  	serial := a.(*asserts.Serial)
   974  
   975  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
   976  	c.Assert(err, IsNil)
   977  	c.Check(privKey, NotNil)
   978  
   979  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
   980  }
   981  
   982  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyPrepareDeviceHook(c *C) {
   983  	r1 := devicestate.MockKeyLength(testKeyLength)
   984  	defer r1()
   985  
   986  	bhv := &devicestatetest.DeviceServiceBehavior{
   987  		RequestIDURLPath: "/svc/request-id",
   988  		SerialURLPath:    "/svc/serial",
   989  	}
   990  	bhv.PostPreflight = func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) {
   991  		c.Check(r.Header.Get("X-Extra-Header"), Equals, "extra")
   992  	}
   993  
   994  	mockServer := s.mockServer(c, "REQID-1", bhv)
   995  	defer mockServer.Close()
   996  
   997  	// setup state as will be done by first-boot
   998  	// & have a gadget with a prepare-device hook
   999  	s.state.Lock()
  1000  	defer s.state.Unlock()
  1001  
  1002  	pDBhv := &devicestatetest.PrepareDeviceBehavior{
  1003  		DeviceSvcURL: mockServer.URL + "/svc/",
  1004  		Headers: map[string]string{
  1005  			"x-extra-header": "extra",
  1006  		},
  1007  		RegBody: map[string]string{
  1008  			"mac": "00:00:00:00:ff:00",
  1009  		},
  1010  		ProposedSerial: "Y9999",
  1011  	}
  1012  
  1013  	r2 := devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), pDBhv)
  1014  	defer r2()
  1015  
  1016  	// as device-service.url is set, should not need to do this but just in case
  1017  	r3 := devicestate.MockBaseStoreURL(mockServer.URL + "/direct/baad/")
  1018  	defer r3()
  1019  
  1020  	s.makeModelAssertionInState(c, "canonical", "pc2", map[string]interface{}{
  1021  		"architecture": "amd64",
  1022  		"kernel":       "pc-kernel",
  1023  		"gadget":       "gadget",
  1024  	})
  1025  
  1026  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1027  		Brand: "canonical",
  1028  		Model: "pc2",
  1029  	})
  1030  
  1031  	// avoid full seeding
  1032  	s.seeding()
  1033  
  1034  	// runs the whole device registration process, note that the
  1035  	// device is not seeded yet
  1036  	s.state.Unlock()
  1037  	s.settle(c)
  1038  	s.state.Lock()
  1039  
  1040  	// without a seeded device, there is no become-operational change
  1041  	becomeOperational := s.findBecomeOperationalChange()
  1042  	c.Assert(becomeOperational, IsNil)
  1043  
  1044  	// now mark it as seeded
  1045  	s.state.Set("seeded", true)
  1046  	// and run the device registration again
  1047  	s.state.Unlock()
  1048  	s.settle(c)
  1049  	s.state.Lock()
  1050  
  1051  	becomeOperational = s.findBecomeOperationalChange()
  1052  	c.Assert(becomeOperational, NotNil)
  1053  
  1054  	c.Check(becomeOperational.Status().Ready(), Equals, true)
  1055  	c.Check(becomeOperational.Err(), IsNil)
  1056  
  1057  	device, err := devicestatetest.Device(s.state)
  1058  	c.Assert(err, IsNil)
  1059  	c.Check(device.Brand, Equals, "canonical")
  1060  	c.Check(device.Model, Equals, "pc2")
  1061  	c.Check(device.Serial, Equals, "Y9999")
  1062  
  1063  	a, err := s.db.Find(asserts.SerialType, map[string]string{
  1064  		"brand-id": "canonical",
  1065  		"model":    "pc2",
  1066  		"serial":   "Y9999",
  1067  	})
  1068  	c.Assert(err, IsNil)
  1069  	serial := a.(*asserts.Serial)
  1070  
  1071  	var details map[string]interface{}
  1072  	err = yaml.Unmarshal(serial.Body(), &details)
  1073  	c.Assert(err, IsNil)
  1074  
  1075  	c.Check(details, DeepEquals, map[string]interface{}{
  1076  		"mac": "00:00:00:00:ff:00",
  1077  	})
  1078  
  1079  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
  1080  	c.Assert(err, IsNil)
  1081  	c.Check(privKey, NotNil)
  1082  
  1083  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
  1084  }
  1085  
  1086  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyWithHookAndNewProxy(c *C) {
  1087  	s.testFullDeviceRegistrationHappyWithHookAndProxy(c, true)
  1088  }
  1089  
  1090  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyWithHookAndOldProxy(c *C) {
  1091  	s.testFullDeviceRegistrationHappyWithHookAndProxy(c, false)
  1092  }
  1093  
  1094  func (s *deviceMgrSerialSuite) testFullDeviceRegistrationHappyWithHookAndProxy(c *C, newEnough bool) {
  1095  	r1 := devicestate.MockKeyLength(testKeyLength)
  1096  	defer r1()
  1097  
  1098  	var reqID string
  1099  	var storeVersion string
  1100  	head := func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) {
  1101  		w.Header().Set("Snap-Store-Version", storeVersion)
  1102  	}
  1103  	bhv := &devicestatetest.DeviceServiceBehavior{
  1104  		Head: head,
  1105  	}
  1106  	svcPath := "/svc/"
  1107  	if newEnough {
  1108  		reqID = "REQID-42"
  1109  		storeVersion = "6"
  1110  		bhv.PostPreflight = func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) {
  1111  			c.Check(r.Header.Get("X-Snap-Device-Service-URL"), Matches, "http://[^/]*/bad/svc/")
  1112  			c.Check(r.Header.Get("X-Extra-Header"), Equals, "extra")
  1113  		}
  1114  		svcPath = "/bad/svc/"
  1115  	} else {
  1116  		reqID = "REQID-41"
  1117  		storeVersion = "5"
  1118  		bhv.RequestIDURLPath = "/svc/request-id"
  1119  		bhv.SerialURLPath = "/svc/serial"
  1120  		bhv.PostPreflight = func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) {
  1121  			c.Check(r.Header.Get("X-Extra-Header"), Equals, "extra")
  1122  		}
  1123  	}
  1124  
  1125  	mockServer := s.mockServer(c, reqID, bhv)
  1126  	defer mockServer.Close()
  1127  
  1128  	// setup state as will be done by first-boot
  1129  	// & have a gadget with a prepare-device hook
  1130  	s.state.Lock()
  1131  	defer s.state.Unlock()
  1132  
  1133  	pDBhv := &devicestatetest.PrepareDeviceBehavior{
  1134  		DeviceSvcURL: mockServer.URL + svcPath,
  1135  		Headers: map[string]string{
  1136  			"x-extra-header": "extra",
  1137  		},
  1138  	}
  1139  	r2 := devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), pDBhv)
  1140  	defer r2()
  1141  
  1142  	// as device-service.url is set, should not need to do this but just in case
  1143  	r3 := devicestate.MockBaseStoreURL(mockServer.URL + "/direct/baad/")
  1144  	defer r3()
  1145  
  1146  	tr := config.NewTransaction(s.state)
  1147  	c.Assert(tr.Set("core", "proxy.store", "foo"), IsNil)
  1148  	tr.Commit()
  1149  	operatorAcct := assertstest.NewAccount(s.storeSigning, "foo-operator", nil, "")
  1150  
  1151  	// have a store assertion.
  1152  	stoAs, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{
  1153  		"store":       "foo",
  1154  		"url":         mockServer.URL,
  1155  		"operator-id": operatorAcct.AccountID(),
  1156  		"timestamp":   time.Now().Format(time.RFC3339),
  1157  	}, nil, "")
  1158  	c.Assert(err, IsNil)
  1159  
  1160  	assertstatetest.AddMany(s.state, operatorAcct, stoAs)
  1161  
  1162  	s.makeModelAssertionInState(c, "canonical", "pc2", map[string]interface{}{
  1163  		"architecture": "amd64",
  1164  		"kernel":       "pc-kernel",
  1165  		"gadget":       "gadget",
  1166  	})
  1167  
  1168  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1169  		Brand: "canonical",
  1170  		Model: "pc2",
  1171  	})
  1172  
  1173  	// mark it as seeded
  1174  	s.state.Set("seeded", true)
  1175  
  1176  	// runs the whole device registration process
  1177  	s.state.Unlock()
  1178  	s.settle(c)
  1179  	s.state.Lock()
  1180  
  1181  	becomeOperational := s.findBecomeOperationalChange()
  1182  	c.Assert(becomeOperational, NotNil)
  1183  
  1184  	c.Check(becomeOperational.Status().Ready(), Equals, true)
  1185  	c.Check(becomeOperational.Err(), IsNil)
  1186  
  1187  	device, err := devicestatetest.Device(s.state)
  1188  	c.Assert(err, IsNil)
  1189  	c.Check(device.Brand, Equals, "canonical")
  1190  	c.Check(device.Model, Equals, "pc2")
  1191  	c.Check(device.Serial, Equals, "9999")
  1192  
  1193  	a, err := s.db.Find(asserts.SerialType, map[string]string{
  1194  		"brand-id": "canonical",
  1195  		"model":    "pc2",
  1196  		"serial":   "9999",
  1197  	})
  1198  	c.Assert(err, IsNil)
  1199  	serial := a.(*asserts.Serial)
  1200  
  1201  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
  1202  	c.Assert(err, IsNil)
  1203  	c.Check(privKey, NotNil)
  1204  
  1205  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
  1206  }
  1207  
  1208  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationErrorBackoff(c *C) {
  1209  	r1 := devicestate.MockKeyLength(testKeyLength)
  1210  	defer r1()
  1211  
  1212  	bhv := &devicestatetest.DeviceServiceBehavior{}
  1213  	mockServer := s.mockServer(c, devicestatetest.ReqIDBadRequest, bhv)
  1214  	defer mockServer.Close()
  1215  
  1216  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
  1217  	defer r2()
  1218  
  1219  	// setup state as will be done by first-boot
  1220  	s.state.Lock()
  1221  	defer s.state.Unlock()
  1222  
  1223  	// sanity
  1224  	c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 0)
  1225  
  1226  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
  1227  		"architecture": "amd64",
  1228  		"kernel":       "pc-kernel",
  1229  		"gadget":       "pc",
  1230  	})
  1231  
  1232  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1233  		Brand: "canonical",
  1234  		Model: "pc",
  1235  	})
  1236  
  1237  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
  1238  	// mark as seeded
  1239  	s.state.Set("seeded", true)
  1240  
  1241  	// try the whole device registration process
  1242  	s.state.Unlock()
  1243  	s.settle(c)
  1244  	s.state.Lock()
  1245  
  1246  	becomeOperational := s.findBecomeOperationalChange()
  1247  	c.Assert(becomeOperational, NotNil)
  1248  	firstTryID := becomeOperational.ID()
  1249  
  1250  	c.Check(becomeOperational.Status().Ready(), Equals, true)
  1251  	c.Check(becomeOperational.Err(), ErrorMatches, `(?s).*cannot deliver device serial request: bad serial-request.*`)
  1252  
  1253  	device, err := devicestatetest.Device(s.state)
  1254  	c.Assert(err, IsNil)
  1255  	c.Check(device.KeyID, Not(Equals), "")
  1256  	keyID := device.KeyID
  1257  
  1258  	c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, time.Now()), Equals, true)
  1259  	c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, time.Now().Add(6*time.Minute)), Equals, false)
  1260  	c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 1)
  1261  
  1262  	// try again the whole device registration process
  1263  	bhv.ReqID = "REQID-1"
  1264  	devicestate.SetLastBecomeOperationalAttempt(s.mgr, time.Now().Add(-15*time.Minute))
  1265  	s.state.Unlock()
  1266  	s.settle(c)
  1267  	s.state.Lock()
  1268  
  1269  	becomeOperational = s.findBecomeOperationalChange(firstTryID)
  1270  	c.Assert(becomeOperational, NotNil)
  1271  
  1272  	c.Check(becomeOperational.Status().Ready(), Equals, true)
  1273  	c.Check(becomeOperational.Err(), IsNil)
  1274  
  1275  	c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 2)
  1276  
  1277  	device, err = devicestatetest.Device(s.state)
  1278  	c.Assert(err, IsNil)
  1279  	c.Check(device.KeyID, Equals, keyID)
  1280  	c.Check(device.Serial, Equals, "10000")
  1281  }
  1282  
  1283  func (s *deviceMgrSerialSuite) TestEnsureBecomeOperationalShouldBackoff(c *C) {
  1284  	t0 := time.Now()
  1285  	c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, t0), Equals, false)
  1286  	c.Check(devicestate.BecomeOperationalBackoff(s.mgr), Equals, 5*time.Minute)
  1287  
  1288  	backoffs := []time.Duration{5, 10, 20, 40, 80, 160, 320, 640, 1440, 1440}
  1289  	t1 := t0
  1290  	for _, m := range backoffs {
  1291  		c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, t1.Add(time.Duration(m-1)*time.Minute)), Equals, true)
  1292  
  1293  		t1 = t1.Add(time.Duration(m+1) * time.Minute)
  1294  		c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, t1), Equals, false)
  1295  		m *= 2
  1296  		if m > (12 * 60) {
  1297  			m = 24 * 60
  1298  		}
  1299  		c.Check(devicestate.BecomeOperationalBackoff(s.mgr), Equals, m*time.Minute)
  1300  	}
  1301  }
  1302  
  1303  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationMismatchedSerial(c *C) {
  1304  	r1 := devicestate.MockKeyLength(testKeyLength)
  1305  	defer r1()
  1306  
  1307  	mockServer := s.mockServer(c, devicestatetest.ReqIDSerialWithBadModel, nil)
  1308  	defer mockServer.Close()
  1309  
  1310  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
  1311  	defer r2()
  1312  
  1313  	// setup state as will be done by first-boot
  1314  	s.state.Lock()
  1315  	defer s.state.Unlock()
  1316  
  1317  	// sanity
  1318  	c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 0)
  1319  
  1320  	devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil)
  1321  
  1322  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
  1323  		"architecture": "amd64",
  1324  		"kernel":       "pc-kernel",
  1325  		"gadget":       "gadget",
  1326  	})
  1327  
  1328  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1329  		Brand: "canonical",
  1330  		Model: "pc",
  1331  	})
  1332  
  1333  	// mark as seeded
  1334  	s.state.Set("seeded", true)
  1335  
  1336  	// try the whole device registration process
  1337  	s.state.Unlock()
  1338  	s.settle(c)
  1339  	s.state.Lock()
  1340  
  1341  	becomeOperational := s.findBecomeOperationalChange()
  1342  	c.Assert(becomeOperational, NotNil)
  1343  
  1344  	c.Check(becomeOperational.Status().Ready(), Equals, true)
  1345  	c.Check(becomeOperational.Err(), ErrorMatches, `(?s).*obtained serial assertion does not match provided device identity information.*`)
  1346  }
  1347  
  1348  func (s *deviceMgrSerialSuite) TestModelAndSerial(c *C) {
  1349  	s.state.Lock()
  1350  	defer s.state.Unlock()
  1351  	// nothing in the state
  1352  	_, err := s.mgr.Model()
  1353  	c.Check(err, Equals, state.ErrNoState)
  1354  	_, err = s.mgr.Serial()
  1355  	c.Check(err, Equals, state.ErrNoState)
  1356  
  1357  	// just brand and model
  1358  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1359  		Brand: "canonical",
  1360  		Model: "pc",
  1361  	})
  1362  	_, err = s.mgr.Model()
  1363  	c.Check(err, Equals, state.ErrNoState)
  1364  	_, err = s.mgr.Serial()
  1365  	c.Check(err, Equals, state.ErrNoState)
  1366  
  1367  	// have a model assertion
  1368  	model := s.brands.Model("canonical", "pc", map[string]interface{}{
  1369  		"gadget":       "pc",
  1370  		"kernel":       "kernel",
  1371  		"architecture": "amd64",
  1372  	})
  1373  	assertstatetest.AddMany(s.state, model)
  1374  
  1375  	mod, err := s.mgr.Model()
  1376  	c.Assert(err, IsNil)
  1377  	c.Assert(mod.BrandID(), Equals, "canonical")
  1378  
  1379  	_, err = s.mgr.Serial()
  1380  	c.Check(err, Equals, state.ErrNoState)
  1381  
  1382  	// have a serial as well
  1383  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1384  		Brand:  "canonical",
  1385  		Model:  "pc",
  1386  		Serial: "8989",
  1387  	})
  1388  	_, err = s.mgr.Model()
  1389  	c.Assert(err, IsNil)
  1390  	_, err = s.mgr.Serial()
  1391  	c.Check(err, Equals, state.ErrNoState)
  1392  
  1393  	// have a serial assertion
  1394  	s.makeSerialAssertionInState(c, "canonical", "pc", "8989")
  1395  
  1396  	_, err = s.mgr.Model()
  1397  	c.Assert(err, IsNil)
  1398  	ser, err := s.mgr.Serial()
  1399  	c.Assert(err, IsNil)
  1400  	c.Check(ser.Serial(), Equals, "8989")
  1401  }
  1402  
  1403  func (s *deviceMgrSerialSuite) TestStoreContextBackendSetDevice(c *C) {
  1404  	s.state.Lock()
  1405  	defer s.state.Unlock()
  1406  
  1407  	scb := s.mgr.StoreContextBackend()
  1408  
  1409  	device, err := scb.Device()
  1410  	c.Check(err, IsNil)
  1411  	c.Check(device, DeepEquals, &auth.DeviceState{})
  1412  
  1413  	err = scb.SetDevice(&auth.DeviceState{Brand: "some-brand"})
  1414  	c.Check(err, IsNil)
  1415  	device, err = scb.Device()
  1416  	c.Check(err, IsNil)
  1417  	c.Check(device, DeepEquals, &auth.DeviceState{Brand: "some-brand"})
  1418  }
  1419  
  1420  func (s *deviceMgrSerialSuite) TestStoreContextBackendModelAndSerial(c *C) {
  1421  	s.state.Lock()
  1422  	defer s.state.Unlock()
  1423  
  1424  	scb := s.mgr.StoreContextBackend()
  1425  
  1426  	// nothing in the state
  1427  	_, err := scb.Model()
  1428  	c.Check(err, Equals, state.ErrNoState)
  1429  	_, err = scb.Serial()
  1430  	c.Check(err, Equals, state.ErrNoState)
  1431  
  1432  	// just brand and model
  1433  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1434  		Brand: "canonical",
  1435  		Model: "pc",
  1436  	})
  1437  	_, err = scb.Model()
  1438  	c.Check(err, Equals, state.ErrNoState)
  1439  	_, err = scb.Serial()
  1440  	c.Check(err, Equals, state.ErrNoState)
  1441  
  1442  	// have a model assertion
  1443  	model := s.brands.Model("canonical", "pc", map[string]interface{}{
  1444  		"gadget":       "pc",
  1445  		"kernel":       "kernel",
  1446  		"architecture": "amd64",
  1447  	})
  1448  	assertstatetest.AddMany(s.state, model)
  1449  
  1450  	mod, err := scb.Model()
  1451  	c.Assert(err, IsNil)
  1452  	c.Assert(mod.BrandID(), Equals, "canonical")
  1453  
  1454  	_, err = scb.Serial()
  1455  	c.Check(err, Equals, state.ErrNoState)
  1456  
  1457  	// have a serial as well
  1458  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1459  		Brand:  "canonical",
  1460  		Model:  "pc",
  1461  		Serial: "8989",
  1462  	})
  1463  	_, err = scb.Model()
  1464  	c.Assert(err, IsNil)
  1465  	_, err = scb.Serial()
  1466  	c.Check(err, Equals, state.ErrNoState)
  1467  
  1468  	// have a serial assertion
  1469  	s.makeSerialAssertionInState(c, "canonical", "pc", "8989")
  1470  
  1471  	_, err = scb.Model()
  1472  	c.Assert(err, IsNil)
  1473  	ser, err := scb.Serial()
  1474  	c.Assert(err, IsNil)
  1475  	c.Check(ser.Serial(), Equals, "8989")
  1476  }
  1477  
  1478  var (
  1479  	devKey, _ = assertstest.GenerateKey(testKeyLength)
  1480  )
  1481  
  1482  func (s *deviceMgrSerialSuite) TestStoreContextBackendDeviceSessionRequestParams(c *C) {
  1483  	s.state.Lock()
  1484  	defer s.state.Unlock()
  1485  
  1486  	// set model as seeding would
  1487  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
  1488  		"architecture": "amd64",
  1489  		"kernel":       "pc-kernel",
  1490  		"gadget":       "pc",
  1491  	})
  1492  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1493  		Brand: "canonical",
  1494  		Model: "pc",
  1495  	})
  1496  
  1497  	scb := s.mgr.StoreContextBackend()
  1498  
  1499  	// nothing there
  1500  	_, err := scb.SignDeviceSessionRequest(nil, "NONCE-1")
  1501  	c.Check(err, ErrorMatches, "internal error: cannot sign a session request without a serial")
  1502  
  1503  	// setup state as done by device initialisation
  1504  	encDevKey, err := asserts.EncodePublicKey(devKey.PublicKey())
  1505  	c.Check(err, IsNil)
  1506  	seriala, err := s.storeSigning.Sign(asserts.SerialType, map[string]interface{}{
  1507  		"brand-id":            "canonical",
  1508  		"model":               "pc",
  1509  		"serial":              "8989",
  1510  		"device-key":          string(encDevKey),
  1511  		"device-key-sha3-384": devKey.PublicKey().ID(),
  1512  		"timestamp":           time.Now().Format(time.RFC3339),
  1513  	}, nil, "")
  1514  	c.Assert(err, IsNil)
  1515  	assertstatetest.AddMany(s.state, seriala)
  1516  	serial := seriala.(*asserts.Serial)
  1517  
  1518  	_, err = scb.SignDeviceSessionRequest(serial, "NONCE-1")
  1519  	c.Check(err, ErrorMatches, "internal error: inconsistent state with serial but no device key")
  1520  
  1521  	// have a key
  1522  	devicestate.KeypairManager(s.mgr).Put(devKey)
  1523  
  1524  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1525  		Brand:  "canonical",
  1526  		Model:  "pc",
  1527  		Serial: "8989",
  1528  		KeyID:  devKey.PublicKey().ID(),
  1529  	})
  1530  
  1531  	sessReq, err := scb.SignDeviceSessionRequest(serial, "NONCE-1")
  1532  	c.Assert(err, IsNil)
  1533  
  1534  	// correctly signed with device key
  1535  	err = asserts.SignatureCheck(sessReq, devKey.PublicKey())
  1536  	c.Check(err, IsNil)
  1537  
  1538  	c.Check(sessReq.BrandID(), Equals, "canonical")
  1539  	c.Check(sessReq.Model(), Equals, "pc")
  1540  	c.Check(sessReq.Serial(), Equals, "8989")
  1541  	c.Check(sessReq.Nonce(), Equals, "NONCE-1")
  1542  }
  1543  
  1544  func (s *deviceMgrSerialSuite) TestStoreContextBackendProxyStore(c *C) {
  1545  	mockServer := s.mockServer(c, "", nil)
  1546  	defer mockServer.Close()
  1547  	s.state.Lock()
  1548  	defer s.state.Unlock()
  1549  
  1550  	scb := s.mgr.StoreContextBackend()
  1551  
  1552  	// nothing in the state
  1553  	_, err := scb.ProxyStore()
  1554  	c.Check(err, Equals, state.ErrNoState)
  1555  
  1556  	// have a store referenced
  1557  	tr := config.NewTransaction(s.state)
  1558  	err = tr.Set("core", "proxy.store", "foo")
  1559  	tr.Commit()
  1560  	c.Assert(err, IsNil)
  1561  
  1562  	_, err = scb.ProxyStore()
  1563  	c.Check(err, Equals, state.ErrNoState)
  1564  
  1565  	operatorAcct := assertstest.NewAccount(s.storeSigning, "foo-operator", nil, "")
  1566  
  1567  	// have a store assertion.
  1568  	stoAs, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{
  1569  		"store":       "foo",
  1570  		"operator-id": operatorAcct.AccountID(),
  1571  		"url":         mockServer.URL,
  1572  		"timestamp":   time.Now().Format(time.RFC3339),
  1573  	}, nil, "")
  1574  	c.Assert(err, IsNil)
  1575  
  1576  	assertstatetest.AddMany(s.state, operatorAcct, stoAs)
  1577  
  1578  	sto, err := scb.ProxyStore()
  1579  	c.Assert(err, IsNil)
  1580  	c.Assert(sto.Store(), Equals, "foo")
  1581  	c.Assert(sto.URL().String(), Equals, mockServer.URL)
  1582  }
  1583  
  1584  func (s *deviceMgrSerialSuite) TestInitialRegistrationContext(c *C) {
  1585  	s.state.Lock()
  1586  	defer s.state.Unlock()
  1587  
  1588  	// have a model assertion
  1589  	model, err := s.storeSigning.Sign(asserts.ModelType, map[string]interface{}{
  1590  		"series":       "16",
  1591  		"brand-id":     "canonical",
  1592  		"model":        "pc",
  1593  		"gadget":       "pc-gadget",
  1594  		"kernel":       "kernel",
  1595  		"architecture": "amd64",
  1596  		"timestamp":    time.Now().Format(time.RFC3339),
  1597  	}, nil, "")
  1598  	c.Assert(err, IsNil)
  1599  	err = assertstate.Add(s.state, model)
  1600  	c.Assert(err, IsNil)
  1601  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1602  		Brand: "canonical",
  1603  		Model: "pc",
  1604  	})
  1605  
  1606  	// TODO: will need to pass in a task later
  1607  	regCtx, err := devicestate.RegistrationCtx(s.mgr, nil)
  1608  	c.Assert(err, IsNil)
  1609  	c.Assert(regCtx, NotNil)
  1610  
  1611  	c.Check(regCtx.ForRemodeling(), Equals, false)
  1612  
  1613  	device, err := regCtx.Device()
  1614  	c.Check(err, IsNil)
  1615  	c.Check(device, DeepEquals, &auth.DeviceState{
  1616  		Brand: "canonical",
  1617  		Model: "pc",
  1618  	})
  1619  
  1620  	c.Check(regCtx.Model(), DeepEquals, model)
  1621  
  1622  	c.Check(regCtx.GadgetForSerialRequestConfig(), Equals, "pc-gadget")
  1623  	c.Check(regCtx.SerialRequestExtraHeaders(), HasLen, 0)
  1624  	ancillary := regCtx.SerialRequestAncillaryAssertions()
  1625  	c.Check(ancillary, HasLen, 1)
  1626  	reqMod, ok := ancillary[0].(*asserts.Model)
  1627  	c.Assert(ok, Equals, true)
  1628  	c.Check(reqMod, DeepEquals, model)
  1629  
  1630  }
  1631  
  1632  func (s *deviceMgrSerialSuite) TestNewEnoughProxyParse(c *C) {
  1633  	s.state.Lock()
  1634  	defer s.state.Unlock()
  1635  
  1636  	log, restore := logger.MockLogger()
  1637  	defer restore()
  1638  	os.Setenv("SNAPD_DEBUG", "1")
  1639  	defer os.Unsetenv("SNAPD_DEBUG")
  1640  
  1641  	badURL := &url.URL{Opaque: "%a"} // url.Parse(badURL.String()) needs to fail, which isn't easy :-)
  1642  	c.Check(devicestate.NewEnoughProxy(s.state, badURL, http.DefaultClient), Equals, false)
  1643  	c.Check(log.String(), Matches, "(?m).* DEBUG: Cannot check whether proxy store supports a custom serial vault: parse .*")
  1644  }
  1645  
  1646  func (s *deviceMgrSerialSuite) TestNewEnoughProxy(c *C) {
  1647  	s.state.Lock()
  1648  	defer s.state.Unlock()
  1649  
  1650  	expectedUserAgent := snapdenv.UserAgent()
  1651  	log, restore := logger.MockLogger()
  1652  	defer restore()
  1653  	os.Setenv("SNAPD_DEBUG", "1")
  1654  	defer os.Unsetenv("SNAPD_DEBUG")
  1655  
  1656  	expecteds := []string{
  1657  		`Head \"?http://\S+\"?: EOF`,
  1658  		`Head request returned 403 Forbidden.`,
  1659  		`Bogus Snap-Store-Version header "5pre1".`,
  1660  		``,
  1661  	}
  1662  
  1663  	n := 0
  1664  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1665  		c.Check(r.Header.Get("User-Agent"), Equals, expectedUserAgent)
  1666  		n++
  1667  		switch n {
  1668  		case 1:
  1669  			conn, _, err := w.(http.Hijacker).Hijack()
  1670  			c.Assert(err, IsNil)
  1671  			conn.Close()
  1672  		case 2:
  1673  			w.WriteHeader(403)
  1674  		case 3:
  1675  			w.Header().Set("Snap-Store-Version", "5pre1")
  1676  			w.WriteHeader(200)
  1677  		case 4:
  1678  			w.Header().Set("Snap-Store-Version", "5")
  1679  			w.WriteHeader(200)
  1680  		case 5:
  1681  			w.Header().Set("Snap-Store-Version", "6")
  1682  			w.WriteHeader(200)
  1683  		default:
  1684  			c.Errorf("expected %d results, now on %d", len(expecteds), n)
  1685  		}
  1686  	}))
  1687  	defer server.Close()
  1688  
  1689  	u, err := url.Parse(server.URL)
  1690  	c.Assert(err, IsNil)
  1691  	for _, expected := range expecteds {
  1692  		log.Reset()
  1693  		c.Check(devicestate.NewEnoughProxy(s.state, u, http.DefaultClient), Equals, false)
  1694  		if len(expected) > 0 {
  1695  			expected = "(?m).* DEBUG: Cannot check whether proxy store supports a custom serial vault: " + expected
  1696  		}
  1697  		c.Check(log.String(), Matches, expected)
  1698  	}
  1699  	c.Check(n, Equals, len(expecteds))
  1700  
  1701  	// and success at last
  1702  	log.Reset()
  1703  	c.Check(devicestate.NewEnoughProxy(s.state, u, http.DefaultClient), Equals, true)
  1704  	c.Check(log.String(), Equals, "")
  1705  	c.Check(n, Equals, len(expecteds)+1)
  1706  }
  1707  
  1708  func (s *deviceMgrSerialSuite) testDoRequestSerialReregistration(c *C, setAncillary func(origSerial *asserts.Serial)) *state.Task {
  1709  	mockServer := s.mockServer(c, "REQID-1", nil)
  1710  	defer mockServer.Close()
  1711  
  1712  	restore := devicestate.MockBaseStoreURL(mockServer.URL)
  1713  	defer restore()
  1714  
  1715  	// setup state as after initial registration
  1716  	s.state.Lock()
  1717  	defer s.state.Unlock()
  1718  
  1719  	s.makeModelAssertionInState(c, "my-brand", "my-model", map[string]interface{}{
  1720  		"architecture": "amd64",
  1721  		"kernel":       "pc-kernel",
  1722  		"gadget":       "pc",
  1723  	})
  1724  
  1725  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
  1726  
  1727  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1728  		Brand:  "my-brand",
  1729  		Model:  "my-model",
  1730  		KeyID:  devKey.PublicKey().ID(),
  1731  		Serial: "9999",
  1732  	})
  1733  	devicestate.KeypairManager(s.mgr).Put(devKey)
  1734  
  1735  	// have a serial assertion
  1736  	serial0 := s.makeSerialAssertionInState(c, "my-brand", "my-model", "9999")
  1737  	// give a chance to the test to setup returning a stream vs
  1738  	// just the serial assertion
  1739  	if setAncillary != nil {
  1740  		setAncillary(serial0)
  1741  	}
  1742  
  1743  	new := s.brands.Model("rereg-brand", "rereg-model", map[string]interface{}{
  1744  		"architecture": "amd64",
  1745  		"kernel":       "pc-kernel",
  1746  		"gadget":       "pc",
  1747  	})
  1748  	cur, err := s.mgr.Model()
  1749  	c.Assert(err, IsNil)
  1750  
  1751  	s.newFakeStore = func(devBE storecontext.DeviceBackend) snapstate.StoreService {
  1752  		mod, err := devBE.Model()
  1753  		c.Check(err, IsNil)
  1754  		if err == nil {
  1755  			c.Check(mod, DeepEquals, new)
  1756  		}
  1757  		return nil
  1758  	}
  1759  
  1760  	remodCtx, err := devicestate.RemodelCtx(s.state, cur, new)
  1761  	c.Assert(err, IsNil)
  1762  	c.Check(remodCtx.Kind(), Equals, devicestate.ReregRemodel)
  1763  
  1764  	t := s.state.NewTask("request-serial", "test")
  1765  	chg := s.state.NewChange("remodel", "...")
  1766  	// associate with context
  1767  	remodCtx.Init(chg)
  1768  	chg.AddTask(t)
  1769  
  1770  	// sanity
  1771  	regCtx, err := devicestate.RegistrationCtx(s.mgr, t)
  1772  	c.Assert(err, IsNil)
  1773  	c.Check(regCtx, Equals, remodCtx.(devicestate.RegistrationContext))
  1774  
  1775  	// avoid full seeding
  1776  	s.seeding()
  1777  
  1778  	s.state.Unlock()
  1779  	s.se.Ensure()
  1780  	s.se.Wait()
  1781  	s.state.Lock()
  1782  
  1783  	return t
  1784  }
  1785  
  1786  func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistration(c *C) {
  1787  	assertstest.AddMany(s.storeSigning, s.brands.AccountsAndKeys("rereg-brand")...)
  1788  
  1789  	t := s.testDoRequestSerialReregistration(c, nil)
  1790  
  1791  	s.state.Lock()
  1792  	defer s.state.Unlock()
  1793  	chg := t.Change()
  1794  
  1795  	c.Check(chg.Status(), Equals, state.DoneStatus, Commentf("%s", t.Log()))
  1796  	c.Check(chg.Err(), IsNil)
  1797  	device, err := devicestatetest.Device(s.state)
  1798  	c.Check(err, IsNil)
  1799  	c.Check(device.Serial, Equals, "9999")
  1800  	_, err = s.db.Find(asserts.SerialType, map[string]string{
  1801  		"brand-id": "rereg-brand",
  1802  		"model":    "rereg-model",
  1803  		"serial":   "9999",
  1804  	})
  1805  	c.Assert(err, IsNil)
  1806  }
  1807  
  1808  func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistrationStreamFromService(c *C) {
  1809  	setAncillary := func(_ *asserts.Serial) {
  1810  		// sets up such that re-registration returns a stream
  1811  		// of assertions
  1812  		s.ancillary = s.brands.AccountsAndKeys("rereg-brand")
  1813  	}
  1814  
  1815  	t := s.testDoRequestSerialReregistration(c, setAncillary)
  1816  
  1817  	s.state.Lock()
  1818  	defer s.state.Unlock()
  1819  	chg := t.Change()
  1820  
  1821  	c.Check(chg.Status(), Equals, state.DoneStatus, Commentf("%s", t.Log()))
  1822  	c.Check(chg.Err(), IsNil)
  1823  	device, err := devicestatetest.Device(s.state)
  1824  	c.Check(err, IsNil)
  1825  	c.Check(device.Serial, Equals, "9999")
  1826  	_, err = s.db.Find(asserts.SerialType, map[string]string{
  1827  		"brand-id": "rereg-brand",
  1828  		"model":    "rereg-model",
  1829  		"serial":   "9999",
  1830  	})
  1831  	c.Assert(err, IsNil)
  1832  }
  1833  
  1834  func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistrationIncompleteStreamFromService(c *C) {
  1835  	setAncillary := func(_ *asserts.Serial) {
  1836  		// will produce an incomplete stream!
  1837  		s.ancillary = s.brands.AccountsAndKeys("rereg-brand")[:1]
  1838  	}
  1839  
  1840  	t := s.testDoRequestSerialReregistration(c, setAncillary)
  1841  
  1842  	s.state.Lock()
  1843  	defer s.state.Unlock()
  1844  	chg := t.Change()
  1845  
  1846  	c.Check(chg.Status(), Equals, state.ErrorStatus, Commentf("%s", t.Log()))
  1847  	c.Check(chg.Err(), ErrorMatches, `(?ms).*cannot accept stream of assertions from device service:.*`)
  1848  }
  1849  
  1850  func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistrationDoubleSerialStreamFromService(c *C) {
  1851  	setAncillary := func(serial0 *asserts.Serial) {
  1852  		// will produce a stream with confusingly two serial
  1853  		// assertions
  1854  		s.ancillary = s.brands.AccountsAndKeys("rereg-brand")
  1855  		s.ancillary = append(s.ancillary, serial0)
  1856  	}
  1857  
  1858  	t := s.testDoRequestSerialReregistration(c, setAncillary)
  1859  
  1860  	s.state.Lock()
  1861  	defer s.state.Unlock()
  1862  	chg := t.Change()
  1863  
  1864  	c.Check(chg.Status(), Equals, state.ErrorStatus, Commentf("%s", t.Log()))
  1865  	c.Check(chg.Err(), ErrorMatches, `(?ms).*cannot accept more than a single device serial assertion from the device service.*`)
  1866  }
  1867  
  1868  func (s *deviceMgrSerialSuite) TestDeviceRegistrationNotInInstallMode(c *C) {
  1869  	st := s.state
  1870  	// setup state as will be done by first-boot
  1871  	st.Lock()
  1872  	s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{
  1873  		"architecture": "amd64",
  1874  		"kernel":       "pc-kernel",
  1875  		"gadget":       "pc",
  1876  	})
  1877  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1878  		Brand: "canonical",
  1879  		Model: "pc",
  1880  	})
  1881  	// mark it as seeded
  1882  	st.Set("seeded", true)
  1883  	// set run mode to "install"
  1884  	devicestate.SetSystemMode(s.mgr, "install")
  1885  	st.Unlock()
  1886  
  1887  	// runs the whole device registration process
  1888  	// but it will not actually create any changes because
  1889  	s.settle(c)
  1890  
  1891  	st.Lock()
  1892  	defer st.Unlock()
  1893  	becomeOperational := s.findBecomeOperationalChange()
  1894  	c.Assert(becomeOperational, IsNil)
  1895  }
  1896  
  1897  func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationUC20Happy(c *C) {
  1898  	defer sysdb.InjectTrusted([]asserts.Assertion{s.storeSigning.TrustedKey})()
  1899  
  1900  	r1 := devicestate.MockKeyLength(testKeyLength)
  1901  	defer r1()
  1902  
  1903  	mockServer := s.mockServer(c, "REQID-1", nil)
  1904  	defer mockServer.Close()
  1905  
  1906  	r2 := devicestate.MockBaseStoreURL(mockServer.URL)
  1907  	defer r2()
  1908  
  1909  	// setup state as will be done by first-boot
  1910  	s.state.Lock()
  1911  	defer s.state.Unlock()
  1912  
  1913  	s.makeModelAssertionInState(c, "canonical", "pc-20", map[string]interface{}{
  1914  		"architecture": "amd64",
  1915  		// UC20
  1916  		"base": "core20",
  1917  		"snaps": []interface{}{
  1918  			map[string]interface{}{
  1919  				"name":            "pc-kernel",
  1920  				"id":              snaptest.AssertedSnapID("oc-kernel"),
  1921  				"type":            "kernel",
  1922  				"default-channel": "20",
  1923  			},
  1924  			map[string]interface{}{
  1925  				"name":            "pc",
  1926  				"id":              snaptest.AssertedSnapID("pc"),
  1927  				"type":            "gadget",
  1928  				"default-channel": "20",
  1929  			},
  1930  		},
  1931  	})
  1932  
  1933  	devicestatetest.SetDevice(s.state, &auth.DeviceState{
  1934  		Brand: "canonical",
  1935  		Model: "pc-20",
  1936  	})
  1937  
  1938  	// save is available
  1939  	devicestate.SetSaveAvailable(s.mgr, true)
  1940  
  1941  	// avoid full seeding
  1942  	s.seeding()
  1943  
  1944  	becomeOperational := s.findBecomeOperationalChange()
  1945  	c.Check(becomeOperational, IsNil)
  1946  
  1947  	devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil)
  1948  	// mark it as seeded
  1949  	s.state.Set("seeded", true)
  1950  	// skip boot ok logic
  1951  	devicestate.SetBootOkRan(s.mgr, true)
  1952  
  1953  	// runs the whole device registration process
  1954  	s.state.Unlock()
  1955  	s.settle(c)
  1956  	s.state.Lock()
  1957  
  1958  	becomeOperational = s.findBecomeOperationalChange()
  1959  	c.Assert(becomeOperational, NotNil)
  1960  
  1961  	c.Check(becomeOperational.Status().Ready(), Equals, true)
  1962  	c.Check(becomeOperational.Err(), IsNil)
  1963  
  1964  	device, err := devicestatetest.Device(s.state)
  1965  	c.Assert(err, IsNil)
  1966  	c.Check(device.Brand, Equals, "canonical")
  1967  	c.Check(device.Model, Equals, "pc-20")
  1968  	c.Check(device.Serial, Equals, "9999")
  1969  
  1970  	ok := false
  1971  	select {
  1972  	case <-s.mgr.Registered():
  1973  		ok = true
  1974  	case <-time.After(5 * time.Second):
  1975  		c.Fatal("should have been marked registered")
  1976  	}
  1977  	c.Check(ok, Equals, true)
  1978  
  1979  	a, err := s.db.Find(asserts.SerialType, map[string]string{
  1980  		"brand-id": "canonical",
  1981  		"model":    "pc-20",
  1982  		"serial":   "9999",
  1983  	})
  1984  	c.Assert(err, IsNil)
  1985  	serial := a.(*asserts.Serial)
  1986  
  1987  	privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID())
  1988  	c.Assert(err, IsNil)
  1989  	c.Check(privKey, NotNil)
  1990  
  1991  	c.Check(device.KeyID, Equals, privKey.PublicKey().ID())
  1992  
  1993  	// check that keypair manager is under save
  1994  	c.Check(osutil.IsDirectory(filepath.Join(dirs.SnapDeviceSaveDir, "private-keys-v1")), Equals, true)
  1995  	c.Check(filepath.Join(dirs.SnapDeviceDir, "private-keys-v1"), testutil.FileAbsent)
  1996  
  1997  	// check that the serial was saved to the device save assertion db
  1998  	// as well
  1999  	savedb, err := sysdb.OpenAt(dirs.SnapDeviceSaveDir)
  2000  	c.Assert(err, IsNil)
  2001  	// a copy of model was saved there
  2002  	_, err = savedb.Find(asserts.ModelType, map[string]string{
  2003  		"series":   "16",
  2004  		"brand-id": "canonical",
  2005  		"model":    "pc-20",
  2006  	})
  2007  	c.Assert(err, IsNil)
  2008  	// a copy of serial was backed up there
  2009  	_, err = savedb.Find(asserts.SerialType, map[string]string{
  2010  		"brand-id": "canonical",
  2011  		"model":    "pc-20",
  2012  		"serial":   "9999",
  2013  	})
  2014  	c.Assert(err, IsNil)
  2015  }