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