github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/asserts/assertstest/assertstest.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 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 assertstest provides helpers for testing code that involves assertions. 21 package assertstest 22 23 import ( 24 "bytes" 25 "crypto/rand" 26 "crypto/rsa" 27 "encoding/base64" 28 "fmt" 29 "io" 30 "os/exec" 31 "strings" 32 "time" 33 34 "golang.org/x/crypto/openpgp/armor" 35 "golang.org/x/crypto/openpgp/packet" 36 37 "github.com/snapcore/snapd/asserts" 38 "github.com/snapcore/snapd/randutil" 39 ) 40 41 // GenerateKey generates a private/public key pair of the given bits. It panics on error. 42 func GenerateKey(bits int) (asserts.PrivateKey, *rsa.PrivateKey) { 43 priv, err := rsa.GenerateKey(rand.Reader, bits) 44 if err != nil { 45 panic(fmt.Errorf("failed to create private key: %v", err)) 46 } 47 return asserts.RSAPrivateKey(priv), priv 48 } 49 50 // ReadPrivKey reads a PGP private key (either armored or simply base64 encoded). It panics on error. 51 func ReadPrivKey(pk string) (asserts.PrivateKey, *rsa.PrivateKey) { 52 rd := bytes.NewReader([]byte(pk)) 53 blk, err := armor.Decode(rd) 54 var body io.Reader 55 if err == nil { 56 body = blk.Body 57 } else { 58 rd.Seek(0, 0) 59 // try unarmored 60 body = base64.NewDecoder(base64.StdEncoding, rd) 61 } 62 pkt, err := packet.Read(body) 63 if err != nil { 64 panic(err) 65 } 66 67 pkPkt := pkt.(*packet.PrivateKey) 68 rsaPrivKey, ok := pkPkt.PrivateKey.(*rsa.PrivateKey) 69 if !ok { 70 panic("not a RSA key") 71 } 72 73 return asserts.RSAPrivateKey(rsaPrivKey), rsaPrivKey 74 } 75 76 // A sample developer key. 77 // See systestkeys for a prebuilt set of trusted keys and assertions. 78 const ( 79 DevKey = `-----BEGIN PGP PRIVATE KEY BLOCK----- 80 Version: GnuPG v1 81 82 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 132 =5Myf 133 -----END PGP PRIVATE KEY BLOCK----- 134 ` 135 136 DevKeyID = "EAD4DbLxK_kn0gzNCXOs3kd6DeMU3f-L6BEsSEuJGBqCORR0gXkdDxMbOm11mRFu" 137 138 DevKeyPGPFingerprint = "966e70f4b9f257a2772f8f354a423d28aaea4b4f" 139 ) 140 141 // GPGImportKey imports the given PGP armored key into the GnuPG setup at homedir. It panics on error. 142 func GPGImportKey(homedir, armoredKey string) { 143 path, err := exec.LookPath("gpg1") 144 if err != nil { 145 path, err = exec.LookPath("gpg") 146 } 147 if err != nil { 148 panic(err) 149 } 150 gpg := exec.Command(path, "--homedir", homedir, "-q", "--batch", "--import", "--armor") 151 gpg.Stdin = bytes.NewBufferString(armoredKey) 152 out, err := gpg.CombinedOutput() 153 if err != nil { 154 panic(fmt.Errorf("cannot import test key into GPG setup at %q: %v (%q)", homedir, err, out)) 155 } 156 } 157 158 // A SignerDB can sign assertions using its key pairs. 159 type SignerDB interface { 160 Sign(assertType *asserts.AssertionType, headers map[string]interface{}, body []byte, keyID string) (asserts.Assertion, error) 161 } 162 163 // NewAccount creates an account assertion for username, it fills in values for other missing headers as needed. It panics on error. 164 func NewAccount(db SignerDB, username string, otherHeaders map[string]interface{}, keyID string) *asserts.Account { 165 if otherHeaders == nil { 166 otherHeaders = make(map[string]interface{}) 167 } 168 otherHeaders["username"] = username 169 if otherHeaders["account-id"] == nil { 170 otherHeaders["account-id"] = randutil.RandomString(32) 171 } 172 if otherHeaders["display-name"] == nil { 173 otherHeaders["display-name"] = strings.ToTitle(username[:1]) + username[1:] 174 } 175 if otherHeaders["validation"] == nil { 176 otherHeaders["validation"] = "unproven" 177 } 178 if otherHeaders["timestamp"] == nil { 179 otherHeaders["timestamp"] = time.Now().Format(time.RFC3339) 180 } 181 a, err := db.Sign(asserts.AccountType, otherHeaders, nil, keyID) 182 if err != nil { 183 panic(err) 184 } 185 return a.(*asserts.Account) 186 } 187 188 // NewAccountKey creates an account-key assertion for the account, it fills in values for missing headers as needed. In panics on error. 189 func NewAccountKey(db SignerDB, acct *asserts.Account, otherHeaders map[string]interface{}, pubKey asserts.PublicKey, keyID string) *asserts.AccountKey { 190 if otherHeaders == nil { 191 otherHeaders = make(map[string]interface{}) 192 } 193 otherHeaders["account-id"] = acct.AccountID() 194 otherHeaders["public-key-sha3-384"] = pubKey.ID() 195 if otherHeaders["name"] == nil { 196 otherHeaders["name"] = "default" 197 } 198 if otherHeaders["since"] == nil { 199 otherHeaders["since"] = time.Now().Format(time.RFC3339) 200 } 201 encodedPubKey, err := asserts.EncodePublicKey(pubKey) 202 if err != nil { 203 panic(err) 204 } 205 a, err := db.Sign(asserts.AccountKeyType, otherHeaders, encodedPubKey, keyID) 206 if err != nil { 207 panic(err) 208 } 209 return a.(*asserts.AccountKey) 210 } 211 212 // SigningDB embeds a signing assertion database with a default private key and assigned authority id. 213 // Sign will use the assigned authority id. 214 // "" can be passed for keyID to Sign and PublicKey to use the default key. 215 type SigningDB struct { 216 AuthorityID string 217 KeyID string 218 219 *asserts.Database 220 } 221 222 // NewSigningDB creates a test signing assertion db with the given defaults. It panics on error. 223 func NewSigningDB(authorityID string, privKey asserts.PrivateKey) *SigningDB { 224 db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{}) 225 if err != nil { 226 panic(err) 227 } 228 err = db.ImportKey(privKey) 229 if err != nil { 230 panic(err) 231 } 232 return &SigningDB{ 233 AuthorityID: authorityID, 234 KeyID: privKey.PublicKey().ID(), 235 Database: db, 236 } 237 } 238 239 func (db *SigningDB) Sign(assertType *asserts.AssertionType, headers map[string]interface{}, body []byte, keyID string) (asserts.Assertion, error) { 240 if _, ok := headers["authority-id"]; !ok { 241 // copy before modifying 242 headers2 := make(map[string]interface{}, len(headers)+1) 243 for h, v := range headers { 244 headers2[h] = v 245 } 246 headers = headers2 247 headers["authority-id"] = db.AuthorityID 248 } 249 if keyID == "" { 250 keyID = db.KeyID 251 } 252 return db.Database.Sign(assertType, headers, body, keyID) 253 } 254 255 func (db *SigningDB) PublicKey(keyID string) (asserts.PublicKey, error) { 256 if keyID == "" { 257 keyID = db.KeyID 258 } 259 return db.Database.PublicKey(keyID) 260 } 261 262 // StoreStack realises a store-like set of founding trusted assertions and signing setup. 263 type StoreStack struct { 264 // Trusted authority assertions. 265 TrustedAccount *asserts.Account 266 TrustedKey *asserts.AccountKey 267 Trusted []asserts.Assertion 268 269 // Generic authority assertions. 270 GenericAccount *asserts.Account 271 GenericKey *asserts.AccountKey 272 GenericModelsKey *asserts.AccountKey 273 Generic []asserts.Assertion 274 GenericClassicModel *asserts.Model 275 276 // Signing assertion db that signs with the root private key. 277 RootSigning *SigningDB 278 279 // The store-like signing functionality that signs with a store key, setup to also store assertions if desired. It stores a default account-key for the store private key, see also the StoreStack.Key method. 280 *SigningDB 281 } 282 283 // StoreKeys holds a set of store private keys. 284 type StoreKeys struct { 285 Root asserts.PrivateKey 286 Store asserts.PrivateKey 287 Generic asserts.PrivateKey 288 GenericModels asserts.PrivateKey 289 } 290 291 var ( 292 rootPrivKey, _ = GenerateKey(1024) 293 storePrivKey, _ = GenerateKey(752) 294 genericPrivKey, _ = GenerateKey(752) 295 genericModelsPrivKey, _ = GenerateKey(752) 296 297 pregenKeys = StoreKeys{ 298 Root: rootPrivKey, 299 Store: storePrivKey, 300 Generic: genericPrivKey, 301 GenericModels: genericModelsPrivKey, 302 } 303 ) 304 305 // NewStoreStack creates a new store assertion stack. It panics on error. 306 // Optional keys specify private keys to use for the various roles. 307 func NewStoreStack(authorityID string, keys *StoreKeys) *StoreStack { 308 if keys == nil { 309 keys = &pregenKeys 310 } 311 312 rootSigning := NewSigningDB(authorityID, keys.Root) 313 ts := time.Now().Format(time.RFC3339) 314 trustedAcct := NewAccount(rootSigning, authorityID, map[string]interface{}{ 315 "account-id": authorityID, 316 "validation": "verified", 317 "timestamp": ts, 318 }, "") 319 trustedKey := NewAccountKey(rootSigning, trustedAcct, map[string]interface{}{ 320 "name": "root", 321 "since": ts, 322 }, keys.Root.PublicKey(), "") 323 trusted := []asserts.Assertion{trustedAcct, trustedKey} 324 325 genericAcct := NewAccount(rootSigning, "generic", map[string]interface{}{ 326 "account-id": "generic", 327 "validation": "verified", 328 "timestamp": ts, 329 }, "") 330 331 err := rootSigning.ImportKey(keys.GenericModels) 332 if err != nil { 333 panic(err) 334 } 335 genericModelsKey := NewAccountKey(rootSigning, genericAcct, map[string]interface{}{ 336 "name": "models", 337 "since": ts, 338 }, keys.GenericModels.PublicKey(), "") 339 generic := []asserts.Assertion{genericAcct, genericModelsKey} 340 341 db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ 342 Backstore: asserts.NewMemoryBackstore(), 343 Trusted: trusted, 344 OtherPredefined: generic, 345 }) 346 if err != nil { 347 panic(err) 348 } 349 err = db.ImportKey(keys.Store) 350 if err != nil { 351 panic(err) 352 } 353 storeKey := NewAccountKey(rootSigning, trustedAcct, map[string]interface{}{ 354 "name": "store", 355 }, keys.Store.PublicKey(), "") 356 err = db.Add(storeKey) 357 if err != nil { 358 panic(err) 359 } 360 361 err = db.ImportKey(keys.Generic) 362 if err != nil { 363 panic(err) 364 } 365 genericKey := NewAccountKey(rootSigning, genericAcct, map[string]interface{}{ 366 "name": "serials", 367 "since": ts, 368 }, keys.Generic.PublicKey(), "") 369 err = db.Add(genericKey) 370 if err != nil { 371 panic(err) 372 } 373 374 a, err := rootSigning.Sign(asserts.ModelType, map[string]interface{}{ 375 "authority-id": "generic", 376 "series": "16", 377 "brand-id": "generic", 378 "model": "generic-classic", 379 "classic": "true", 380 "timestamp": ts, 381 }, nil, genericModelsKey.PublicKeyID()) 382 if err != nil { 383 panic(err) 384 } 385 genericClassicMod := a.(*asserts.Model) 386 387 return &StoreStack{ 388 TrustedAccount: trustedAcct, 389 TrustedKey: trustedKey, 390 Trusted: trusted, 391 392 GenericAccount: genericAcct, 393 GenericKey: genericKey, 394 GenericModelsKey: genericModelsKey, 395 Generic: generic, 396 GenericClassicModel: genericClassicMod, 397 398 RootSigning: rootSigning, 399 400 SigningDB: &SigningDB{ 401 AuthorityID: authorityID, 402 KeyID: storeKey.PublicKeyID(), 403 Database: db, 404 }, 405 } 406 } 407 408 // StoreAccountKey retrieves one of the account-key assertions for the signing keys of the simulated store signing database. 409 // "" for keyID means the default one. It panics on error. 410 func (ss *StoreStack) StoreAccountKey(keyID string) *asserts.AccountKey { 411 if keyID == "" { 412 keyID = ss.KeyID 413 } 414 key, err := ss.Find(asserts.AccountKeyType, map[string]string{ 415 "account-id": ss.AuthorityID, 416 "public-key-sha3-384": keyID, 417 }) 418 if asserts.IsNotFound(err) { 419 return nil 420 } 421 if err != nil { 422 panic(err) 423 } 424 return key.(*asserts.AccountKey) 425 } 426 427 // MockBuiltinBaseDeclaration mocks the builtin base-declaration exposed by asserts.BuiltinBaseDeclaration. 428 func MockBuiltinBaseDeclaration(headers []byte) (restore func()) { 429 var prevHeaders []byte 430 decl := asserts.BuiltinBaseDeclaration() 431 if decl != nil { 432 prevHeaders, _ = decl.Signature() 433 } 434 435 err := asserts.InitBuiltinBaseDeclaration(headers) 436 if err != nil { 437 panic(err) 438 } 439 440 return func() { 441 err := asserts.InitBuiltinBaseDeclaration(prevHeaders) 442 if err != nil { 443 panic(err) 444 } 445 } 446 } 447 448 // FakeAssertionWithBody builds a fake assertion with the given body 449 // and layered headers. A fake assertion cannot be verified or added 450 // to a database or properly encoded. It can still be useful for unit 451 // tests but shouldn't be used in integration tests. 452 func FakeAssertionWithBody(body []byte, headerLayers ...map[string]interface{}) asserts.Assertion { 453 headers := map[string]interface{}{ 454 "sign-key-sha3-384": "Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij", 455 } 456 for _, h := range headerLayers { 457 for k, v := range h { 458 headers[k] = v 459 } 460 } 461 462 _, hasTimestamp := headers["timestamp"] 463 _, hasSince := headers["since"] 464 if !(hasTimestamp || hasSince) { 465 headers["timestamp"] = time.Now().Format(time.RFC3339) 466 } 467 468 a, err := asserts.Assemble(headers, body, nil, []byte("AXNpZw==")) 469 if err != nil { 470 panic(fmt.Sprintf("cannot build fake assertion: %v", err)) 471 } 472 return a 473 } 474 475 // FakeAssertion builds a fake assertion with given layered headers 476 // and an empty body. A fake assertion cannot be verified or added to 477 // a database or properly encoded. It can still be useful for unit 478 // tests but shouldn't be used in integration tests. 479 func FakeAssertion(headerLayers ...map[string]interface{}) asserts.Assertion { 480 return FakeAssertionWithBody(nil, headerLayers...) 481 } 482 483 type accuDB interface { 484 Add(asserts.Assertion) error 485 } 486 487 // AddMany conveniently adds the given assertions to the db. 488 // It is idempotent but otherwise panics on error. 489 func AddMany(db accuDB, assertions ...asserts.Assertion) { 490 for _, a := range assertions { 491 err := db.Add(a) 492 if _, ok := err.(*asserts.RevisionError); !ok { 493 if err != nil { 494 panic(fmt.Sprintf("cannot add test assertions: %v", err)) 495 } 496 } 497 } 498 } 499 500 // SigningAccounts manages a set of brand or user accounts, 501 // with their keys that can sign models etc. 502 type SigningAccounts struct { 503 store *StoreStack 504 505 signing map[string]*SigningDB 506 507 accts map[string]*asserts.Account 508 acctKeys map[string]*asserts.AccountKey 509 } 510 511 // NewSigningAccounts creates a new SigningAccounts instance. 512 func NewSigningAccounts(store *StoreStack) *SigningAccounts { 513 return &SigningAccounts{ 514 store: store, 515 signing: make(map[string]*SigningDB), 516 accts: make(map[string]*asserts.Account), 517 acctKeys: make(map[string]*asserts.AccountKey), 518 } 519 } 520 521 func (sa *SigningAccounts) Register(accountID string, brandPrivKey asserts.PrivateKey, extra map[string]interface{}) *SigningDB { 522 brandSigning := NewSigningDB(accountID, brandPrivKey) 523 sa.signing[accountID] = brandSigning 524 525 acctHeaders := map[string]interface{}{ 526 "account-id": accountID, 527 } 528 for k, v := range extra { 529 acctHeaders[k] = v 530 } 531 532 brandAcct := NewAccount(sa.store, accountID, acctHeaders, "") 533 sa.accts[accountID] = brandAcct 534 535 brandPubKey, err := brandSigning.PublicKey("") 536 if err != nil { 537 panic(err) 538 } 539 brandAcctKey := NewAccountKey(sa.store, brandAcct, nil, brandPubKey, "") 540 sa.acctKeys[accountID] = brandAcctKey 541 542 return brandSigning 543 } 544 545 func (sa *SigningAccounts) Account(accountID string) *asserts.Account { 546 if acct := sa.accts[accountID]; acct != nil { 547 return acct 548 } 549 panic(fmt.Sprintf("unknown test account-id: %s", accountID)) 550 } 551 552 func (sa *SigningAccounts) AccountKey(accountID string) *asserts.AccountKey { 553 if acctKey := sa.acctKeys[accountID]; acctKey != nil { 554 return acctKey 555 } 556 panic(fmt.Sprintf("unknown test account-id: %s", accountID)) 557 } 558 559 func (sa *SigningAccounts) PublicKey(accountID string) asserts.PublicKey { 560 pubKey, err := sa.Signing(accountID).PublicKey("") 561 if err != nil { 562 panic(err) 563 } 564 return pubKey 565 } 566 567 func (sa *SigningAccounts) Signing(accountID string) *SigningDB { 568 // convenience 569 if accountID == sa.store.RootSigning.AuthorityID { 570 return sa.store.RootSigning 571 } 572 if signer := sa.signing[accountID]; signer != nil { 573 return signer 574 } 575 panic(fmt.Sprintf("unknown test account-id: %s", accountID)) 576 } 577 578 // Model creates a new model for accountID. accountID can also be the account-id of the underlying store stack. 579 func (sa *SigningAccounts) Model(accountID, model string, extras ...map[string]interface{}) *asserts.Model { 580 headers := map[string]interface{}{ 581 "series": "16", 582 "brand-id": accountID, 583 "model": model, 584 "timestamp": time.Now().Format(time.RFC3339), 585 } 586 for _, extra := range extras { 587 for k, v := range extra { 588 headers[k] = v 589 } 590 } 591 592 signer := sa.Signing(accountID) 593 594 modelAs, err := signer.Sign(asserts.ModelType, headers, nil, "") 595 if err != nil { 596 panic(err) 597 } 598 return modelAs.(*asserts.Model) 599 } 600 601 // AccountsAndKeys returns the account and account-key for each given 602 // accountID in that order. 603 func (sa *SigningAccounts) AccountsAndKeys(accountIDs ...string) []asserts.Assertion { 604 res := make([]asserts.Assertion, 0, 2*len(accountIDs)) 605 for _, accountID := range accountIDs { 606 res = append(res, sa.Account(accountID)) 607 res = append(res, sa.AccountKey(accountID)) 608 } 609 return res 610 }