// ReadKeyRing reads one or more public/private keys. Unsupported keys are // ignored as long as at least a single valid key is found. func ReadKeyRing(r io.Reader) (el EntityList, err error) { packets := packet.NewReader(r) var lastUnsupportedError error for { var e *Entity e, err = ReadEntity(packets) if err != nil { // TODO: warn about skipped unsupported/unreadable keys if _, ok := err.(errors.UnsupportedError); ok { lastUnsupportedError = err err = readToNextPublicKey(packets) } else if _, ok := err.(errors.StructuralError); ok { // Skip unreadable, badly-formatted keys lastUnsupportedError = err err = readToNextPublicKey(packets) } if err == io.EOF { err = nil break } if err != nil { el = nil break } } else { el = append(el, e) } } if len(el) == 0 && err == nil { err = lastUnsupportedError } return }
// DecryptBytes takes in base64-encoded encrypted bytes and the base64-encoded // private key and decrypts it. A bytes.Buffer is returned to allow the caller // to do useful thing with it (get it as a []byte, get it as a string, use it // as an io.Reader, etc), and also because this function doesn't know if what // comes out is binary data or a string, so let the caller decide. func DecryptBytes(encodedCrypt, privKey string) (*bytes.Buffer, error) { privKeyBytes, err := base64.StdEncoding.DecodeString(privKey) if err != nil { return nil, fmt.Errorf("Error decoding base64 private key: %s", err) } cryptBytes, err := base64.StdEncoding.DecodeString(encodedCrypt) if err != nil { return nil, fmt.Errorf("Error decoding base64 crypted bytes: %s", err) } entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(privKeyBytes))) if err != nil { return nil, fmt.Errorf("Error parsing private key: %s", err) } entityList := &openpgp.EntityList{entity} md, err := openpgp.ReadMessage(bytes.NewBuffer(cryptBytes), entityList, nil, nil) if err != nil { return nil, fmt.Errorf("Error decrypting the messages: %s", err) } ptBuf := bytes.NewBuffer(nil) ptBuf.ReadFrom(md.UnverifiedBody) return ptBuf, nil }
func TestFetchKeybasePubkeys(t *testing.T) { testset := []string{"keybase:jefferai", "keybase:hashicorp"} ret, err := FetchKeybasePubkeys(testset) if err != nil { t.Fatalf("bad: %v", err) } fingerprints := []string{} for _, user := range testset { data, err := base64.StdEncoding.DecodeString(ret[user]) if err != nil { t.Fatalf("error decoding key for user %s: %v", user, err) } entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data))) if err != nil { t.Fatalf("error parsing key for user %s: %v", user, err) } fingerprints = append(fingerprints, hex.EncodeToString(entity.PrimaryKey.Fingerprint[:])) } exp := []string{ "0f801f518ec853daff611e836528efcac6caa3db", "91a6e7f85d05c65630bef18951852d87348ffc4c", } if !reflect.DeepEqual(fingerprints, exp) { t.Fatalf("fingerprints do not match; expected \n%#v\ngot\n%#v\n", exp, fingerprints) } }
// GetEntities takes in a string array of base64-encoded PGP keys and returns // the openpgp Entities func GetEntities(pgpKeys []string) ([]*openpgp.Entity, error) { ret := make([]*openpgp.Entity, 0, len(pgpKeys)) for _, keystring := range pgpKeys { data, err := base64.StdEncoding.DecodeString(keystring) if err != nil { return nil, fmt.Errorf("Error decoding given PGP key: %s", err) } entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data))) if err != nil { return nil, fmt.Errorf("Error parsing given PGP key: %s", err) } ret = append(ret, entity) } return ret, nil }
func TestPubKeyFilesFlagSetKeybase(t *testing.T) { tempDir, err := ioutil.TempDir("", "vault-test") if err != nil { t.Fatalf("Error creating temporary directory: %s", err) } defer os.RemoveAll(tempDir) err = ioutil.WriteFile(tempDir+"/pubkey2", []byte(pubKey2), 0755) if err != nil { t.Fatalf("Error writing pub key 2 to temp file: %s", err) } pkf := new(PubKeyFilesFlag) err = pkf.Set("keybase:jefferai,@" + tempDir + "/pubkey2" + ",keybase:hashicorp") if err != nil { t.Fatalf("err: %s", err) } fingerprints := []string{} for _, pubkey := range []string(*pkf) { keyBytes, err := base64.StdEncoding.DecodeString(pubkey) if err != nil { t.Fatalf("bad: %v", err) } pubKeyBuf := bytes.NewBuffer(keyBytes) reader := packet.NewReader(pubKeyBuf) entity, err := openpgp.ReadEntity(reader) if err != nil { t.Fatalf("bad: %v", err) } if entity == nil { t.Fatalf("nil entity encountered") } fingerprints = append(fingerprints, hex.EncodeToString(entity.PrimaryKey.Fingerprint[:])) } exp := []string{ "0f801f518ec853daff611e836528efcac6caa3db", "cf3d4694c9f57b28cb4092c2eb832c67eb5e8957", "91a6e7f85d05c65630bef18951852d87348ffc4c", } if !reflect.DeepEqual(fingerprints, exp) { t.Fatalf("bad: got \n%#v\nexpected\n%#v\n", fingerprints, exp) } }
// Validate is used to sanity check the seal configuration func (s *SealConfig) Validate() error { if s.SecretShares < 1 { return fmt.Errorf("shares must be at least one") } if s.SecretThreshold < 1 { return fmt.Errorf("threshold must be at least one") } if s.SecretShares > 1 && s.SecretThreshold == 1 { return fmt.Errorf("threshold must be greater than one for multiple shares") } if s.SecretShares > 255 { return fmt.Errorf("shares must be less than 256") } if s.SecretThreshold > 255 { return fmt.Errorf("threshold must be less than 256") } if s.SecretThreshold > s.SecretShares { return fmt.Errorf("threshold cannot be larger than shares") } if s.StoredShares > s.SecretShares { return fmt.Errorf("stored keys cannot be larger than shares") } if len(s.PGPKeys) > 0 && len(s.PGPKeys) != s.SecretShares-s.StoredShares { return fmt.Errorf("count mismatch between number of provided PGP keys and number of shares") } if len(s.PGPKeys) > 0 { for _, keystring := range s.PGPKeys { data, err := base64.StdEncoding.DecodeString(keystring) if err != nil { return fmt.Errorf("Error decoding given PGP key: %s", err) } _, err = openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data))) if err != nil { return fmt.Errorf("Error parsing given PGP key: %s", err) } } } return nil }
func parseDecryptAndTestUnsealKeys(t *testing.T, input, rootToken string, fingerprints bool, backupKeys map[string][]string, backupKeysB64 map[string][]string, core *vault.Core) { decoder := base64.StdEncoding priv1Bytes, err := decoder.DecodeString(pgpkeys.TestPrivKey1) if err != nil { t.Fatalf("Error decoding bytes for private key 1: %s", err) } priv2Bytes, err := decoder.DecodeString(pgpkeys.TestPrivKey2) if err != nil { t.Fatalf("Error decoding bytes for private key 2: %s", err) } priv3Bytes, err := decoder.DecodeString(pgpkeys.TestPrivKey3) if err != nil { t.Fatalf("Error decoding bytes for private key 3: %s", err) } privBytes := [][]byte{ priv1Bytes, priv2Bytes, priv3Bytes, } testFunc := func(bkeys map[string][]string) { var re *regexp.Regexp if fingerprints { re, err = regexp.Compile("\\s*Key\\s+\\d+\\s+fingerprint:\\s+([0-9a-fA-F]+);\\s+value:\\s+(.*)") } else { re, err = regexp.Compile("\\s*Key\\s+\\d+:\\s+(.*)") } if err != nil { t.Fatalf("Error compiling regex: %s", err) } matches := re.FindAllStringSubmatch(input, -1) if len(matches) != 4 { t.Fatalf("Unexpected number of keys returned, got %d, matches was \n\n%#v\n\n, input was \n\n%s\n\n", len(matches), matches, input) } encodedKeys := []string{} matchedFingerprints := []string{} for _, tuple := range matches { if fingerprints { if len(tuple) != 3 { t.Fatalf("Key not found: %#v", tuple) } matchedFingerprints = append(matchedFingerprints, tuple[1]) encodedKeys = append(encodedKeys, tuple[2]) } else { if len(tuple) != 2 { t.Fatalf("Key not found: %#v", tuple) } encodedKeys = append(encodedKeys, tuple[1]) } } if bkeys != nil && len(matchedFingerprints) != 0 { testMap := map[string][]string{} for i, v := range matchedFingerprints { testMap[v] = append(testMap[v], encodedKeys[i]) sort.Strings(testMap[v]) } if !reflect.DeepEqual(testMap, bkeys) { t.Fatalf("test map and backup map do not match, test map is\n%#v\nbackup map is\n%#v", testMap, bkeys) } } unsealKeys := []string{} ptBuf := bytes.NewBuffer(nil) for i, privKeyBytes := range privBytes { if i > 2 { break } ptBuf.Reset() entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(privKeyBytes))) if err != nil { t.Fatalf("Error parsing private key %d: %s", i, err) } var keyBytes []byte keyBytes, err = base64.StdEncoding.DecodeString(encodedKeys[i]) if err != nil { t.Fatalf("Error decoding key %d: %s", i, err) } entityList := &openpgp.EntityList{entity} md, err := openpgp.ReadMessage(bytes.NewBuffer(keyBytes), entityList, nil, nil) if err != nil { t.Fatalf("Error decrypting with key %d (%s): %s", i, encodedKeys[i], err) } ptBuf.ReadFrom(md.UnverifiedBody) unsealKeys = append(unsealKeys, ptBuf.String()) } err = core.Seal(rootToken) if err != nil { t.Fatalf("Error sealing vault with provided root token: %s", err) } for i, unsealKey := range unsealKeys { unsealBytes, err := hex.DecodeString(unsealKey) if err != nil { t.Fatalf("Error hex decoding unseal key %s: %s", unsealKey, err) } unsealed, err := core.Unseal(unsealBytes) if err != nil { t.Fatalf("Error using unseal key %s: %s", unsealKey, err) } if i >= 2 && !unsealed { t.Fatalf("Error: Provided two unseal keys but core is not unsealed") } } } testFunc(backupKeysB64) }
// ReadMessage parses an OpenPGP message that may be signed and/or encrypted. // The given KeyRing should contain both public keys (for signature // verification) and, possibly encrypted, private keys for decrypting. // If config is nil, sensible defaults will be used. func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) { var p packet.Packet var symKeys []*packet.SymmetricKeyEncrypted var pubKeys []keyEnvelopePair var se *packet.SymmetricallyEncrypted packets := packet.NewReader(r) md = new(MessageDetails) md.IsEncrypted = true // The message, if encrypted, starts with a number of packets // containing an encrypted decryption key. The decryption key is either // encrypted to a public key, or with a passphrase. This loop // collects these packets. ParsePackets: for { p, err = packets.Next() if err != nil { return nil, err } switch p := p.(type) { case *packet.SymmetricKeyEncrypted: // This packet contains the decryption key encrypted with a passphrase. md.IsSymmetricallyEncrypted = true symKeys = append(symKeys, p) case *packet.EncryptedKey: // This packet contains the decryption key encrypted to a public key. md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) switch p.Algo { case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal: break default: continue } var keys []Key if p.KeyId == 0 { keys = keyring.DecryptionKeys() } else { keys = keyring.KeysById(p.KeyId) } for _, k := range keys { pubKeys = append(pubKeys, keyEnvelopePair{k, p}) } case *packet.SymmetricallyEncrypted: se = p break ParsePackets case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: // This message isn't encrypted. if len(symKeys) != 0 || len(pubKeys) != 0 { return nil, errors.StructuralError("key material not followed by encrypted message") } packets.Unread(p) return readSignedMessage(packets, nil, keyring) } } var candidates []Key var decrypted io.ReadCloser // Now that we have the list of encrypted keys we need to decrypt at // least one of them or, if we cannot, we need to call the prompt // function so that it can decrypt a key or give us a passphrase. FindKey: for { // See if any of the keys already have a private key available candidates = candidates[:0] candidateFingerprints := make(map[string]bool) for _, pk := range pubKeys { if pk.key.PrivateKey == nil { continue } if !pk.key.PrivateKey.Encrypted { if len(pk.encryptedKey.Key) == 0 { pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) } if len(pk.encryptedKey.Key) == 0 { continue } decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) if err != nil && err != errors.ErrKeyIncorrect { return nil, err } if decrypted != nil { md.DecryptedWith = pk.key break FindKey } } else { fpr := string(pk.key.PublicKey.Fingerprint[:]) if v := candidateFingerprints[fpr]; v { continue } candidates = append(candidates, pk.key) candidateFingerprints[fpr] = true } } if len(candidates) == 0 && len(symKeys) == 0 { return nil, errors.ErrKeyIncorrect } if prompt == nil { return nil, errors.ErrKeyIncorrect } passphrase, err := prompt(candidates, len(symKeys) != 0) if err != nil { return nil, err } // Try the symmetric passphrase first if len(symKeys) != 0 && passphrase != nil { for _, s := range symKeys { key, cipherFunc, err := s.Decrypt(passphrase) if err == nil { decrypted, err = se.Decrypt(cipherFunc, key) if err != nil && err != errors.ErrKeyIncorrect { return nil, err } if decrypted != nil { break FindKey } } } } } md.decrypted = decrypted if err := packets.Push(decrypted); err != nil { return nil, err } return readSignedMessage(packets, md, keyring) }
func checkDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, issuer *uint64, err error) { var issuerKeyId uint64 var hashFunc crypto.Hash var sigType packet.SignatureType var keys []Key var p packet.Packet packets := packet.NewReader(signature) for { p, err = packets.Next() if err == io.EOF { return nil, nil, errors.ErrUnknownIssuer } if err != nil { return nil, nil, err } switch sig := p.(type) { case *packet.Signature: if sig.IssuerKeyId == nil { return nil, nil, errors.StructuralError("signature doesn't have an issuer") } issuerKeyId = *sig.IssuerKeyId hashFunc = sig.Hash sigType = sig.SigType case *packet.SignatureV3: issuerKeyId = sig.IssuerKeyId hashFunc = sig.Hash sigType = sig.SigType default: return nil, nil, errors.StructuralError("non signature packet found") } keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) if len(keys) > 0 { break } } if len(keys) == 0 { panic("unreachable") } h, wrappedHash, err := hashForSignature(hashFunc, sigType) if err != nil { return nil, nil, err } if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { return nil, nil, err } for _, key := range keys { switch sig := p.(type) { case *packet.Signature: err = key.PublicKey.VerifySignature(h, sig) case *packet.SignatureV3: err = key.PublicKey.VerifySignatureV3(h, sig) default: panic("unreachable") } if err == nil { return key.Entity, &issuerKeyId, nil } } return nil, nil, err }
func TestInit_PGP(t *testing.T) { ui := new(cli.MockUi) c := &InitCommand{ Meta: meta.Meta{ Ui: ui, }, } core := vault.TestCore(t) ln, addr := http.TestServer(t, core) defer ln.Close() init, err := core.Initialized() if err != nil { t.Fatalf("err: %s", err) } if init { t.Fatal("should not be initialized") } tempDir, pubFiles, err := getPubKeyFiles(t) if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) args := []string{ "-address", addr, "-key-shares", "2", "-pgp-keys", pubFiles[0] + ",@" + pubFiles[1] + "," + pubFiles[2], "-key-threshold", "2", "-root-token-pgp-key", pubFiles[0], } // This should fail, as key-shares does not match pgp-keys size if code := c.Run(args); code == 0 { t.Fatalf("bad (command should have failed): %d\n\n%s", code, ui.ErrorWriter.String()) } args = []string{ "-address", addr, "-key-shares", "4", "-pgp-keys", pubFiles[0] + ",@" + pubFiles[1] + "," + pubFiles[2] + "," + pubFiles[3], "-key-threshold", "2", "-root-token-pgp-key", pubFiles[0], } ui.OutputWriter.Reset() if code := c.Run(args); code != 0 { t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) } init, err = core.Initialized() if err != nil { t.Fatalf("err: %s", err) } if !init { t.Fatal("should be initialized") } sealConf, err := core.SealAccess().BarrierConfig() if err != nil { t.Fatalf("err: %s", err) } pgpKeys := []string{} for _, pubFile := range pubFiles { pub, err := pgpkeys.ReadPGPFile(pubFile) if err != nil { t.Fatalf("bad: %v", err) } pgpKeys = append(pgpKeys, pub) } expected := &vault.SealConfig{ Type: "shamir", SecretShares: 4, SecretThreshold: 2, PGPKeys: pgpKeys, } if !reflect.DeepEqual(expected, sealConf) { t.Fatalf("expected:\n%#v\ngot:\n%#v\n", expected, sealConf) } re, err := regexp.Compile("\\s+Initial Root Token:\\s+(.*)") if err != nil { t.Fatalf("Error compiling regex: %s", err) } matches := re.FindAllStringSubmatch(ui.OutputWriter.String(), -1) if len(matches) != 1 { t.Fatalf("Unexpected number of tokens found, got %d", len(matches)) } encRootToken := matches[0][1] privKeyBytes, err := base64.StdEncoding.DecodeString(pgpkeys.TestPrivKey1) if err != nil { t.Fatalf("error decoding private key: %v", err) } ptBuf := bytes.NewBuffer(nil) entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(privKeyBytes))) if err != nil { t.Fatalf("Error parsing private key: %s", err) } var rootBytes []byte rootBytes, err = base64.StdEncoding.DecodeString(encRootToken) if err != nil { t.Fatalf("Error decoding root token: %s", err) } entityList := &openpgp.EntityList{entity} md, err := openpgp.ReadMessage(bytes.NewBuffer(rootBytes), entityList, nil, nil) if err != nil { t.Fatalf("Error decrypting root token: %s", err) } ptBuf.ReadFrom(md.UnverifiedBody) rootToken := ptBuf.String() parseDecryptAndTestUnsealKeys(t, ui.OutputWriter.String(), rootToken, false, nil, nil, core) client, err := c.Client() if err != nil { t.Fatalf("Error fetching client: %v", err) } client.SetToken(rootToken) tokenInfo, err := client.Auth().Token().LookupSelf() if err != nil { t.Fatalf("Error looking up root token info: %v", err) } if tokenInfo.Data["policies"].([]interface{})[0].(string) != "root" { t.Fatalf("expected root policy") } }