mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-15 07:27:15 +00:00
961c878e0d
Switch to using Go modules. This migrates our vendor.json to use Go 1.11's modules system, and replaces the vendor folder with the output of go mod vendor. The vendored code should remain basically the same; I believe some tree shaking of packages and support scripts/licenses/READMEs/etc. happened. This also fixes Travis and our Makefile to no longer use govendor.
507 lines
14 KiB
Go
507 lines
14 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package openpgp
|
|
|
|
import (
|
|
"crypto"
|
|
"hash"
|
|
"io"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/keybase/go-crypto/openpgp/armor"
|
|
"github.com/keybase/go-crypto/openpgp/errors"
|
|
"github.com/keybase/go-crypto/openpgp/packet"
|
|
"github.com/keybase/go-crypto/openpgp/s2k"
|
|
)
|
|
|
|
// DetachSign signs message with the private key from signer (which must
|
|
// already have been decrypted) and writes the signature to w.
|
|
// If config is nil, sensible defaults will be used.
|
|
func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
|
|
return detachSign(w, signer, message, packet.SigTypeBinary, config)
|
|
}
|
|
|
|
// ArmoredDetachSign signs message with the private key from signer (which
|
|
// must already have been decrypted) and writes an armored signature to w.
|
|
// If config is nil, sensible defaults will be used.
|
|
func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) {
|
|
return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config)
|
|
}
|
|
|
|
// DetachSignText signs message (after canonicalising the line endings) with
|
|
// the private key from signer (which must already have been decrypted) and
|
|
// writes the signature to w.
|
|
// If config is nil, sensible defaults will be used.
|
|
func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
|
|
return detachSign(w, signer, message, packet.SigTypeText, config)
|
|
}
|
|
|
|
// ArmoredDetachSignText signs message (after canonicalising the line endings)
|
|
// with the private key from signer (which must already have been decrypted)
|
|
// and writes an armored signature to w.
|
|
// If config is nil, sensible defaults will be used.
|
|
func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
|
|
return armoredDetachSign(w, signer, message, packet.SigTypeText, config)
|
|
}
|
|
|
|
func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
|
|
out, err := armor.Encode(w, SignatureType, nil)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = detachSign(out, signer, message, sigType, config)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return out.Close()
|
|
}
|
|
|
|
// SignWithSigner signs the message of type sigType with s and writes the
|
|
// signature to w.
|
|
// If config is nil, sensible defaults will be used.
|
|
func SignWithSigner(s packet.Signer, w io.Writer, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
|
|
keyId := s.KeyId()
|
|
sig := new(packet.Signature)
|
|
sig.SigType = sigType
|
|
sig.PubKeyAlgo = s.PublicKeyAlgo()
|
|
sig.Hash = config.Hash()
|
|
sig.CreationTime = config.Now()
|
|
sig.IssuerKeyId = &keyId
|
|
|
|
s.Reset()
|
|
|
|
wrapped := s.(hash.Hash)
|
|
|
|
if sigType == packet.SigTypeText {
|
|
wrapped = NewCanonicalTextHash(s)
|
|
}
|
|
|
|
io.Copy(wrapped, message)
|
|
|
|
err = sig.Sign(s, nil, config)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
err = sig.Serialize(w)
|
|
|
|
return
|
|
}
|
|
|
|
func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
|
|
signerSubkey, ok := signer.signingKey(config.Now())
|
|
if !ok {
|
|
err = errors.InvalidArgumentError("no valid signing keys")
|
|
return
|
|
}
|
|
if signerSubkey.PrivateKey == nil {
|
|
return errors.InvalidArgumentError("signing key doesn't have a private key")
|
|
}
|
|
if signerSubkey.PrivateKey.Encrypted {
|
|
return errors.InvalidArgumentError("signing key is encrypted")
|
|
}
|
|
|
|
sig := new(packet.Signature)
|
|
sig.SigType = sigType
|
|
sig.PubKeyAlgo = signerSubkey.PrivateKey.PubKeyAlgo
|
|
sig.Hash = config.Hash()
|
|
sig.CreationTime = config.Now()
|
|
sig.IssuerKeyId = &signerSubkey.PrivateKey.KeyId
|
|
|
|
h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
|
|
if err != nil {
|
|
return
|
|
}
|
|
io.Copy(wrappedHash, message)
|
|
|
|
err = sig.Sign(h, signerSubkey.PrivateKey, config)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return sig.Serialize(w)
|
|
}
|
|
|
|
// FileHints contains metadata about encrypted files. This metadata is, itself,
|
|
// encrypted.
|
|
type FileHints struct {
|
|
// IsBinary can be set to hint that the contents are binary data.
|
|
IsBinary bool
|
|
// FileName hints at the name of the file that should be written. It's
|
|
// truncated to 255 bytes if longer. It may be empty to suggest that the
|
|
// file should not be written to disk. It may be equal to "_CONSOLE" to
|
|
// suggest the data should not be written to disk.
|
|
FileName string
|
|
// ModTime contains the modification time of the file, or the zero time if not applicable.
|
|
ModTime time.Time
|
|
}
|
|
|
|
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
|
|
// The resulting WriteCloser must be closed after the contents of the file have
|
|
// been written.
|
|
// If config is nil, sensible defaults will be used.
|
|
func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
|
|
if hints == nil {
|
|
hints = &FileHints{}
|
|
}
|
|
|
|
key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config)
|
|
if err != nil {
|
|
return
|
|
}
|
|
w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
literaldata := w
|
|
if algo := config.Compression(); algo != packet.CompressionNone {
|
|
var compConfig *packet.CompressionConfig
|
|
if config != nil {
|
|
compConfig = config.CompressionConfig
|
|
}
|
|
literaldata, err = packet.SerializeCompressed(w, algo, compConfig)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
var epochSeconds uint32
|
|
if !hints.ModTime.IsZero() {
|
|
epochSeconds = uint32(hints.ModTime.Unix())
|
|
}
|
|
return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds)
|
|
}
|
|
|
|
// intersectPreferences mutates and returns a prefix of a that contains only
|
|
// the values in the intersection of a and b. The order of a is preserved.
|
|
func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
|
|
var j int
|
|
for _, v := range a {
|
|
for _, v2 := range b {
|
|
if v == v2 {
|
|
a[j] = v
|
|
j++
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return a[:j]
|
|
}
|
|
|
|
func hashToHashId(h crypto.Hash) uint8 {
|
|
v, ok := s2k.HashToHashId(h)
|
|
if !ok {
|
|
panic("tried to convert unknown hash")
|
|
}
|
|
return v
|
|
}
|
|
|
|
// Encrypt encrypts a message to a number of recipients and, optionally, signs
|
|
// it. hints contains optional information, that is also encrypted, that aids
|
|
// the recipients in processing the message. The resulting WriteCloser must
|
|
// be closed after the contents of the file have been written.
|
|
// If config is nil, sensible defaults will be used.
|
|
func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
|
|
var signer *packet.PrivateKey
|
|
if signed != nil {
|
|
signKey, ok := signed.signingKey(config.Now())
|
|
if !ok {
|
|
return nil, errors.InvalidArgumentError("no valid signing keys")
|
|
}
|
|
signer = signKey.PrivateKey
|
|
if signer == nil {
|
|
return nil, errors.InvalidArgumentError("no private key in signing key")
|
|
}
|
|
if signer.Encrypted {
|
|
return nil, errors.InvalidArgumentError("signing key must be decrypted")
|
|
}
|
|
}
|
|
|
|
// These are the possible ciphers that we'll use for the message.
|
|
candidateCiphers := []uint8{
|
|
uint8(packet.CipherAES128),
|
|
uint8(packet.CipherAES256),
|
|
uint8(packet.CipherCAST5),
|
|
}
|
|
// These are the possible hash functions that we'll use for the signature.
|
|
candidateHashes := []uint8{
|
|
hashToHashId(crypto.SHA256),
|
|
hashToHashId(crypto.SHA512),
|
|
hashToHashId(crypto.SHA1),
|
|
hashToHashId(crypto.RIPEMD160),
|
|
}
|
|
|
|
// If no preferences were specified, assume something safe and reasonable.
|
|
defaultCiphers := []uint8{
|
|
uint8(packet.CipherAES128),
|
|
uint8(packet.CipherAES192),
|
|
uint8(packet.CipherAES256),
|
|
uint8(packet.CipherCAST5),
|
|
}
|
|
|
|
defaultHashes := []uint8{
|
|
hashToHashId(crypto.SHA256),
|
|
hashToHashId(crypto.SHA512),
|
|
hashToHashId(crypto.RIPEMD160),
|
|
}
|
|
|
|
encryptKeys := make([]Key, len(to))
|
|
for i := range to {
|
|
var ok bool
|
|
encryptKeys[i], ok = to[i].encryptionKey(config.Now())
|
|
if !ok {
|
|
return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
|
|
}
|
|
|
|
sig := to[i].primaryIdentity().SelfSignature
|
|
|
|
preferredSymmetric := sig.PreferredSymmetric
|
|
if len(preferredSymmetric) == 0 {
|
|
preferredSymmetric = defaultCiphers
|
|
}
|
|
preferredHashes := sig.PreferredHash
|
|
if len(preferredHashes) == 0 {
|
|
preferredHashes = defaultHashes
|
|
}
|
|
candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
|
|
candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
|
|
}
|
|
|
|
if len(candidateCiphers) == 0 {
|
|
return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common ciphers")
|
|
}
|
|
if len(candidateHashes) == 0 {
|
|
return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common hashes")
|
|
}
|
|
|
|
cipher := packet.CipherFunction(candidateCiphers[0])
|
|
// If the cipher specifed by config is a candidate, we'll use that.
|
|
configuredCipher := config.Cipher()
|
|
for _, c := range candidateCiphers {
|
|
cipherFunc := packet.CipherFunction(c)
|
|
if cipherFunc == configuredCipher {
|
|
cipher = cipherFunc
|
|
break
|
|
}
|
|
}
|
|
|
|
var hash crypto.Hash
|
|
for _, hashId := range candidateHashes {
|
|
if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() {
|
|
hash = h
|
|
break
|
|
}
|
|
}
|
|
|
|
// If the hash specified by config is a candidate, we'll use that.
|
|
if configuredHash := config.Hash(); configuredHash.Available() {
|
|
for _, hashId := range candidateHashes {
|
|
if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash {
|
|
hash = h
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if hash == 0 {
|
|
hashId := candidateHashes[0]
|
|
name, ok := s2k.HashIdToString(hashId)
|
|
if !ok {
|
|
name = "#" + strconv.Itoa(int(hashId))
|
|
}
|
|
return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
|
|
}
|
|
|
|
symKey := make([]byte, cipher.KeySize())
|
|
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, key := range encryptKeys {
|
|
if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if signer != nil {
|
|
ops := &packet.OnePassSignature{
|
|
SigType: packet.SigTypeBinary,
|
|
Hash: hash,
|
|
PubKeyAlgo: signer.PubKeyAlgo,
|
|
KeyId: signer.KeyId,
|
|
IsLast: true,
|
|
}
|
|
if err := ops.Serialize(encryptedData); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if hints == nil {
|
|
hints = &FileHints{}
|
|
}
|
|
|
|
w := encryptedData
|
|
if signer != nil {
|
|
// If we need to write a signature packet after the literal
|
|
// data then we need to stop literalData from closing
|
|
// encryptedData.
|
|
w = noOpCloser{encryptedData}
|
|
|
|
}
|
|
var epochSeconds uint32
|
|
if !hints.ModTime.IsZero() {
|
|
epochSeconds = uint32(hints.ModTime.Unix())
|
|
}
|
|
literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if signer != nil {
|
|
return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil
|
|
}
|
|
return literalData, nil
|
|
}
|
|
|
|
// signatureWriter hashes the contents of a message while passing it along to
|
|
// literalData. When closed, it closes literalData, writes a signature packet
|
|
// to encryptedData and then also closes encryptedData.
|
|
type signatureWriter struct {
|
|
encryptedData io.WriteCloser
|
|
literalData io.WriteCloser
|
|
hashType crypto.Hash
|
|
h hash.Hash
|
|
signer *packet.PrivateKey
|
|
config *packet.Config
|
|
}
|
|
|
|
func (s signatureWriter) Write(data []byte) (int, error) {
|
|
s.h.Write(data)
|
|
return s.literalData.Write(data)
|
|
}
|
|
|
|
func (s signatureWriter) Close() error {
|
|
sig := &packet.Signature{
|
|
SigType: packet.SigTypeBinary,
|
|
PubKeyAlgo: s.signer.PubKeyAlgo,
|
|
Hash: s.hashType,
|
|
CreationTime: s.config.Now(),
|
|
IssuerKeyId: &s.signer.KeyId,
|
|
}
|
|
|
|
if err := sig.Sign(s.h, s.signer, s.config); err != nil {
|
|
return err
|
|
}
|
|
if err := s.literalData.Close(); err != nil {
|
|
return err
|
|
}
|
|
if err := sig.Serialize(s.encryptedData); err != nil {
|
|
return err
|
|
}
|
|
return s.encryptedData.Close()
|
|
}
|
|
|
|
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
|
|
// TODO: we have two of these in OpenPGP packages alone. This probably needs
|
|
// to be promoted somewhere more common.
|
|
type noOpCloser struct {
|
|
w io.Writer
|
|
}
|
|
|
|
func (c noOpCloser) Write(data []byte) (n int, err error) {
|
|
return c.w.Write(data)
|
|
}
|
|
|
|
func (c noOpCloser) Close() error {
|
|
return nil
|
|
}
|
|
|
|
// AttachedSign is like openpgp.Encrypt (as in p.crypto/openpgp/write.go), but
|
|
// don't encrypt at all, just sign the literal unencrypted data.
|
|
// Unfortunately we need to duplicate some code here that's already
|
|
// in write.go
|
|
func AttachedSign(out io.WriteCloser, signed Entity, hints *FileHints,
|
|
config *packet.Config) (in io.WriteCloser, err error) {
|
|
|
|
if hints == nil {
|
|
hints = &FileHints{}
|
|
}
|
|
|
|
if config == nil {
|
|
config = &packet.Config{}
|
|
}
|
|
|
|
var signer *packet.PrivateKey
|
|
|
|
signKey, ok := signed.signingKey(config.Now())
|
|
if !ok {
|
|
err = errors.InvalidArgumentError("no valid signing keys")
|
|
return
|
|
}
|
|
signer = signKey.PrivateKey
|
|
if signer == nil {
|
|
err = errors.InvalidArgumentError("no valid signing keys")
|
|
return
|
|
}
|
|
if signer.Encrypted {
|
|
err = errors.InvalidArgumentError("signing key must be decrypted")
|
|
return
|
|
}
|
|
|
|
if algo := config.Compression(); algo != packet.CompressionNone {
|
|
var compConfig *packet.CompressionConfig
|
|
if config != nil {
|
|
compConfig = config.CompressionConfig
|
|
}
|
|
out, err = packet.SerializeCompressed(out, algo, compConfig)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
hasher := crypto.SHA512
|
|
|
|
ops := &packet.OnePassSignature{
|
|
SigType: packet.SigTypeBinary,
|
|
Hash: hasher,
|
|
PubKeyAlgo: signer.PubKeyAlgo,
|
|
KeyId: signer.KeyId,
|
|
IsLast: true,
|
|
}
|
|
|
|
if err = ops.Serialize(out); err != nil {
|
|
return
|
|
}
|
|
|
|
var epochSeconds uint32
|
|
if !hints.ModTime.IsZero() {
|
|
epochSeconds = uint32(hints.ModTime.Unix())
|
|
}
|
|
|
|
// We don't want the literal serializer to closer the output stream
|
|
// since we're going to need to write to it when we finish up the
|
|
// signature stuff.
|
|
in, err = packet.SerializeLiteral(noOpCloser{out}, hints.IsBinary, hints.FileName, epochSeconds)
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// If we need to write a signature packet after the literal
|
|
// data then we need to stop literalData from closing
|
|
// encryptedData.
|
|
in = signatureWriter{out, in, hasher, hasher.New(), signer, config}
|
|
|
|
return
|
|
}
|