github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/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 164 // other missing headers as needed. It panics on error. 165 func NewAccount(db SignerDB, username string, otherHeaders map[string]interface{}, keyID string) *asserts.Account { 166 if otherHeaders == nil { 167 otherHeaders = make(map[string]interface{}) 168 } 169 otherHeaders["username"] = username 170 if otherHeaders["account-id"] == nil { 171 otherHeaders["account-id"] = randutil.RandomString(32) 172 } 173 if otherHeaders["display-name"] == nil { 174 otherHeaders["display-name"] = strings.ToTitle(username[:1]) + username[1:] 175 } 176 if otherHeaders["validation"] == nil { 177 otherHeaders["validation"] = "unproven" 178 } 179 if otherHeaders["timestamp"] == nil { 180 otherHeaders["timestamp"] = time.Now().Format(time.RFC3339) 181 } 182 a, err := db.Sign(asserts.AccountType, otherHeaders, nil, keyID) 183 if err != nil { 184 panic(err) 185 } 186 return a.(*asserts.Account) 187 } 188 189 // NewAccountKey creates an account-key assertion for the account, it fills in 190 // values for missing headers as needed. In panics on error. 191 func NewAccountKey(db SignerDB, acct *asserts.Account, otherHeaders map[string]interface{}, pubKey asserts.PublicKey, keyID string) *asserts.AccountKey { 192 if otherHeaders == nil { 193 otherHeaders = make(map[string]interface{}) 194 } 195 otherHeaders["account-id"] = acct.AccountID() 196 otherHeaders["public-key-sha3-384"] = pubKey.ID() 197 if otherHeaders["name"] == nil { 198 otherHeaders["name"] = "default" 199 } 200 if otherHeaders["since"] == nil { 201 otherHeaders["since"] = time.Now().Format(time.RFC3339) 202 } 203 encodedPubKey, err := asserts.EncodePublicKey(pubKey) 204 if err != nil { 205 panic(err) 206 } 207 a, err := db.Sign(asserts.AccountKeyType, otherHeaders, encodedPubKey, keyID) 208 if err != nil { 209 panic(err) 210 } 211 return a.(*asserts.AccountKey) 212 } 213 214 // SigningDB embeds a signing assertion database with a default private key and assigned authority id. 215 // Sign will use the assigned authority id. 216 // "" can be passed for keyID to Sign and PublicKey to use the default key. 217 type SigningDB struct { 218 AuthorityID string 219 KeyID string 220 221 *asserts.Database 222 } 223 224 // NewSigningDB creates a test signing assertion db with the given defaults. It panics on error. 225 func NewSigningDB(authorityID string, privKey asserts.PrivateKey) *SigningDB { 226 db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{}) 227 if err != nil { 228 panic(err) 229 } 230 err = db.ImportKey(privKey) 231 if err != nil { 232 panic(err) 233 } 234 return &SigningDB{ 235 AuthorityID: authorityID, 236 KeyID: privKey.PublicKey().ID(), 237 Database: db, 238 } 239 } 240 241 func (db *SigningDB) Sign(assertType *asserts.AssertionType, headers map[string]interface{}, body []byte, keyID string) (asserts.Assertion, error) { 242 if _, ok := headers["authority-id"]; !ok { 243 // copy before modifying 244 headers2 := make(map[string]interface{}, len(headers)+1) 245 for h, v := range headers { 246 headers2[h] = v 247 } 248 headers = headers2 249 headers["authority-id"] = db.AuthorityID 250 } 251 if keyID == "" { 252 keyID = db.KeyID 253 } 254 return db.Database.Sign(assertType, headers, body, keyID) 255 } 256 257 func (db *SigningDB) PublicKey(keyID string) (asserts.PublicKey, error) { 258 if keyID == "" { 259 keyID = db.KeyID 260 } 261 return db.Database.PublicKey(keyID) 262 } 263 264 // StoreStack realises a store-like set of founding trusted assertions and signing setup. 265 type StoreStack struct { 266 // Trusted authority assertions. 267 TrustedAccount *asserts.Account 268 TrustedKey *asserts.AccountKey 269 Trusted []asserts.Assertion 270 271 // Generic authority assertions. 272 GenericAccount *asserts.Account 273 GenericKey *asserts.AccountKey 274 GenericModelsKey *asserts.AccountKey 275 Generic []asserts.Assertion 276 GenericClassicModel *asserts.Model 277 278 // Signing assertion db that signs with the root private key. 279 RootSigning *SigningDB 280 281 // 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. 282 *SigningDB 283 } 284 285 // StoreKeys holds a set of store private keys. 286 type StoreKeys struct { 287 Root asserts.PrivateKey 288 Store asserts.PrivateKey 289 Generic asserts.PrivateKey 290 GenericModels asserts.PrivateKey 291 } 292 293 var ( 294 rootPrivKey, _ = GenerateKey(1024) 295 storePrivKey, _ = GenerateKey(752) 296 genericPrivKey, _ = GenerateKey(752) 297 genericModelsPrivKey, _ = GenerateKey(752) 298 299 pregenKeys = StoreKeys{ 300 Root: rootPrivKey, 301 Store: storePrivKey, 302 Generic: genericPrivKey, 303 GenericModels: genericModelsPrivKey, 304 } 305 ) 306 307 // NewStoreStack creates a new store assertion stack. It panics on error. 308 // Optional keys specify private keys to use for the various roles. 309 func NewStoreStack(authorityID string, keys *StoreKeys) *StoreStack { 310 if keys == nil { 311 keys = &pregenKeys 312 } 313 314 rootSigning := NewSigningDB(authorityID, keys.Root) 315 ts := time.Now().Format(time.RFC3339) 316 trustedAcct := NewAccount(rootSigning, authorityID, map[string]interface{}{ 317 "account-id": authorityID, 318 "validation": "verified", 319 "timestamp": ts, 320 }, "") 321 trustedKey := NewAccountKey(rootSigning, trustedAcct, map[string]interface{}{ 322 "name": "root", 323 "since": ts, 324 }, keys.Root.PublicKey(), "") 325 trusted := []asserts.Assertion{trustedAcct, trustedKey} 326 327 genericAcct := NewAccount(rootSigning, "generic", map[string]interface{}{ 328 "account-id": "generic", 329 "validation": "verified", 330 "timestamp": ts, 331 }, "") 332 333 err := rootSigning.ImportKey(keys.GenericModels) 334 if err != nil { 335 panic(err) 336 } 337 genericModelsKey := NewAccountKey(rootSigning, genericAcct, map[string]interface{}{ 338 "name": "models", 339 "since": ts, 340 }, keys.GenericModels.PublicKey(), "") 341 generic := []asserts.Assertion{genericAcct, genericModelsKey} 342 343 db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ 344 Backstore: asserts.NewMemoryBackstore(), 345 Trusted: trusted, 346 OtherPredefined: generic, 347 }) 348 if err != nil { 349 panic(err) 350 } 351 err = db.ImportKey(keys.Store) 352 if err != nil { 353 panic(err) 354 } 355 storeKey := NewAccountKey(rootSigning, trustedAcct, map[string]interface{}{ 356 "name": "store", 357 }, keys.Store.PublicKey(), "") 358 err = db.Add(storeKey) 359 if err != nil { 360 panic(err) 361 } 362 363 err = db.ImportKey(keys.Generic) 364 if err != nil { 365 panic(err) 366 } 367 genericKey := NewAccountKey(rootSigning, genericAcct, map[string]interface{}{ 368 "name": "serials", 369 "since": ts, 370 }, keys.Generic.PublicKey(), "") 371 err = db.Add(genericKey) 372 if err != nil { 373 panic(err) 374 } 375 376 a, err := rootSigning.Sign(asserts.ModelType, map[string]interface{}{ 377 "authority-id": "generic", 378 "series": "16", 379 "brand-id": "generic", 380 "model": "generic-classic", 381 "classic": "true", 382 "timestamp": ts, 383 }, nil, genericModelsKey.PublicKeyID()) 384 if err != nil { 385 panic(err) 386 } 387 genericClassicMod := a.(*asserts.Model) 388 389 return &StoreStack{ 390 TrustedAccount: trustedAcct, 391 TrustedKey: trustedKey, 392 Trusted: trusted, 393 394 GenericAccount: genericAcct, 395 GenericKey: genericKey, 396 GenericModelsKey: genericModelsKey, 397 Generic: generic, 398 GenericClassicModel: genericClassicMod, 399 400 RootSigning: rootSigning, 401 402 SigningDB: &SigningDB{ 403 AuthorityID: authorityID, 404 KeyID: storeKey.PublicKeyID(), 405 Database: db, 406 }, 407 } 408 } 409 410 // StoreAccountKey retrieves one of the account-key assertions for the signing keys of the simulated store signing database. 411 // "" for keyID means the default one. It panics on error. 412 func (ss *StoreStack) StoreAccountKey(keyID string) *asserts.AccountKey { 413 if keyID == "" { 414 keyID = ss.KeyID 415 } 416 key, err := ss.Find(asserts.AccountKeyType, map[string]string{ 417 "account-id": ss.AuthorityID, 418 "public-key-sha3-384": keyID, 419 }) 420 if asserts.IsNotFound(err) { 421 return nil 422 } 423 if err != nil { 424 panic(err) 425 } 426 return key.(*asserts.AccountKey) 427 } 428 429 // MockBuiltinBaseDeclaration mocks the builtin base-declaration exposed by asserts.BuiltinBaseDeclaration. 430 func MockBuiltinBaseDeclaration(headers []byte) (restore func()) { 431 var prevHeaders []byte 432 decl := asserts.BuiltinBaseDeclaration() 433 if decl != nil { 434 prevHeaders, _ = decl.Signature() 435 } 436 437 err := asserts.InitBuiltinBaseDeclaration(headers) 438 if err != nil { 439 panic(err) 440 } 441 442 return func() { 443 err := asserts.InitBuiltinBaseDeclaration(prevHeaders) 444 if err != nil { 445 panic(err) 446 } 447 } 448 } 449 450 // FakeAssertionWithBody builds a fake assertion with the given body 451 // and layered headers. A fake assertion cannot be verified or added 452 // to a database or properly encoded. It can still be useful for unit 453 // tests but shouldn't be used in integration tests. 454 func FakeAssertionWithBody(body []byte, headerLayers ...map[string]interface{}) asserts.Assertion { 455 headers := map[string]interface{}{ 456 "sign-key-sha3-384": "Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij", 457 } 458 for _, h := range headerLayers { 459 for k, v := range h { 460 headers[k] = v 461 } 462 } 463 464 _, hasTimestamp := headers["timestamp"] 465 _, hasSince := headers["since"] 466 if !(hasTimestamp || hasSince) { 467 headers["timestamp"] = time.Now().Format(time.RFC3339) 468 } 469 470 a, err := asserts.Assemble(headers, body, nil, []byte("AXNpZw==")) 471 if err != nil { 472 panic(fmt.Sprintf("cannot build fake assertion: %v", err)) 473 } 474 return a 475 } 476 477 // FakeAssertion builds a fake assertion with given layered headers 478 // and an empty body. A fake assertion cannot be verified or added to 479 // a database or properly encoded. It can still be useful for unit 480 // tests but shouldn't be used in integration tests. 481 func FakeAssertion(headerLayers ...map[string]interface{}) asserts.Assertion { 482 return FakeAssertionWithBody(nil, headerLayers...) 483 } 484 485 type accuDB interface { 486 Add(asserts.Assertion) error 487 } 488 489 // AddMany conveniently adds the given assertions to the db. 490 // It is idempotent but otherwise panics on error. 491 func AddMany(db accuDB, assertions ...asserts.Assertion) { 492 for _, a := range assertions { 493 err := db.Add(a) 494 if _, ok := err.(*asserts.RevisionError); !ok { 495 if err != nil { 496 panic(fmt.Sprintf("cannot add test assertions: %v", err)) 497 } 498 } 499 } 500 } 501 502 // SigningAccounts manages a set of brand or user accounts, 503 // with their keys that can sign models etc. 504 type SigningAccounts struct { 505 store *StoreStack 506 507 signing map[string]*SigningDB 508 509 accts map[string]*asserts.Account 510 acctKeys map[string]*asserts.AccountKey 511 } 512 513 // NewSigningAccounts creates a new SigningAccounts instance. 514 func NewSigningAccounts(store *StoreStack) *SigningAccounts { 515 return &SigningAccounts{ 516 store: store, 517 signing: make(map[string]*SigningDB), 518 accts: make(map[string]*asserts.Account), 519 acctKeys: make(map[string]*asserts.AccountKey), 520 } 521 } 522 523 func (sa *SigningAccounts) Register(accountID string, brandPrivKey asserts.PrivateKey, extra map[string]interface{}) *SigningDB { 524 brandSigning := NewSigningDB(accountID, brandPrivKey) 525 sa.signing[accountID] = brandSigning 526 527 acctHeaders := map[string]interface{}{ 528 "account-id": accountID, 529 } 530 for k, v := range extra { 531 acctHeaders[k] = v 532 } 533 534 brandAcct := NewAccount(sa.store, accountID, acctHeaders, "") 535 sa.accts[accountID] = brandAcct 536 537 brandPubKey, err := brandSigning.PublicKey("") 538 if err != nil { 539 panic(err) 540 } 541 brandAcctKey := NewAccountKey(sa.store, brandAcct, nil, brandPubKey, "") 542 sa.acctKeys[accountID] = brandAcctKey 543 544 return brandSigning 545 } 546 547 func (sa *SigningAccounts) Account(accountID string) *asserts.Account { 548 if acct := sa.accts[accountID]; acct != nil { 549 return acct 550 } 551 panic(fmt.Sprintf("unknown test account-id: %s", accountID)) 552 } 553 554 func (sa *SigningAccounts) AccountKey(accountID string) *asserts.AccountKey { 555 if acctKey := sa.acctKeys[accountID]; acctKey != nil { 556 return acctKey 557 } 558 panic(fmt.Sprintf("unknown test account-id: %s", accountID)) 559 } 560 561 func (sa *SigningAccounts) PublicKey(accountID string) asserts.PublicKey { 562 pubKey, err := sa.Signing(accountID).PublicKey("") 563 if err != nil { 564 panic(err) 565 } 566 return pubKey 567 } 568 569 func (sa *SigningAccounts) Signing(accountID string) *SigningDB { 570 // convenience 571 if accountID == sa.store.RootSigning.AuthorityID { 572 return sa.store.RootSigning 573 } 574 if signer := sa.signing[accountID]; signer != nil { 575 return signer 576 } 577 panic(fmt.Sprintf("unknown test account-id: %s", accountID)) 578 } 579 580 // Model creates a new model for accountID. accountID can also be the account-id of the underlying store stack. 581 func (sa *SigningAccounts) Model(accountID, model string, extras ...map[string]interface{}) *asserts.Model { 582 headers := map[string]interface{}{ 583 "series": "16", 584 "brand-id": accountID, 585 "model": model, 586 "timestamp": time.Now().Format(time.RFC3339), 587 } 588 for _, extra := range extras { 589 for k, v := range extra { 590 headers[k] = v 591 } 592 } 593 594 signer := sa.Signing(accountID) 595 596 modelAs, err := signer.Sign(asserts.ModelType, headers, nil, "") 597 if err != nil { 598 panic(err) 599 } 600 return modelAs.(*asserts.Model) 601 } 602 603 // AccountsAndKeys returns the account and account-key for each given 604 // accountID in that order. 605 func (sa *SigningAccounts) AccountsAndKeys(accountIDs ...string) []asserts.Assertion { 606 res := make([]asserts.Assertion, 0, 2*len(accountIDs)) 607 for _, accountID := range accountIDs { 608 res = append(res, sa.Account(accountID)) 609 res = append(res, sa.AccountKey(accountID)) 610 } 611 return res 612 }