mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-09-07 09:36:44 +00:00
![Paddy](/assets/img/avatar_default.png)
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.
991 lines
28 KiB
Go
991 lines
28 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 packet
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
"crypto/dsa"
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/sha1"
|
|
_ "crypto/sha256"
|
|
_ "crypto/sha512"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"hash"
|
|
"io"
|
|
"math/big"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/keybase/go-crypto/brainpool"
|
|
"github.com/keybase/go-crypto/curve25519"
|
|
"github.com/keybase/go-crypto/ed25519"
|
|
"github.com/keybase/go-crypto/openpgp/ecdh"
|
|
"github.com/keybase/go-crypto/openpgp/elgamal"
|
|
"github.com/keybase/go-crypto/openpgp/errors"
|
|
"github.com/keybase/go-crypto/openpgp/s2k"
|
|
"github.com/keybase/go-crypto/rsa"
|
|
)
|
|
|
|
var (
|
|
// NIST curve P-224
|
|
oidCurveP224 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x21}
|
|
// NIST curve P-256
|
|
oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}
|
|
// NIST curve P-384
|
|
oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22}
|
|
// NIST curve P-521
|
|
oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23}
|
|
// Brainpool curve P-256r1
|
|
oidCurveP256r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}
|
|
// Brainpool curve P-384r1
|
|
oidCurveP384r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B}
|
|
// Brainpool curve P-512r1
|
|
oidCurveP512r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D}
|
|
// EdDSA
|
|
oidEdDSA []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01}
|
|
// cv25519
|
|
oidCurve25519 []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01}
|
|
)
|
|
|
|
const maxOIDLength = 10
|
|
|
|
// ecdsaKey stores the algorithm-specific fields for ECDSA keys.
|
|
// as defined in RFC 6637, Section 9.
|
|
type ecdsaKey struct {
|
|
// oid contains the OID byte sequence identifying the elliptic curve used
|
|
oid []byte
|
|
// p contains the elliptic curve point that represents the public key
|
|
p parsedMPI
|
|
}
|
|
|
|
type edDSAkey struct {
|
|
ecdsaKey
|
|
}
|
|
|
|
func copyFrontFill(dst, src []byte, length int) int {
|
|
if srcLen := len(src); srcLen < length {
|
|
return copy(dst[length-srcLen:], src[:])
|
|
} else {
|
|
return copy(dst[:], src[:])
|
|
}
|
|
}
|
|
|
|
func (e *edDSAkey) Verify(payload []byte, r parsedMPI, s parsedMPI) bool {
|
|
const halfSigSize = ed25519.SignatureSize / 2
|
|
var sig [ed25519.SignatureSize]byte
|
|
|
|
// NOTE: The first byte is 0x40 - MPI header
|
|
// TODO: Maybe clean the code up and use 0x40 as a header when
|
|
// reading and keep only actual number in p field. Find out how
|
|
// other MPIs are stored.
|
|
key := e.p.bytes[1:]
|
|
|
|
// Note: it may happen that R + S do not form 64-byte signature buffer that
|
|
// ed25519 expects, but because we copy it over to an array of exact size,
|
|
// we will always pass correctly sized slice to Verify. Slice too short
|
|
// would make ed25519 panic().
|
|
copyFrontFill(sig[:halfSigSize], r.bytes, halfSigSize)
|
|
copyFrontFill(sig[halfSigSize:], s.bytes, halfSigSize)
|
|
|
|
return ed25519.Verify(key, payload, sig[:])
|
|
}
|
|
|
|
// parseOID reads the OID for the curve as defined in RFC 6637, Section 9.
|
|
func parseOID(r io.Reader) (oid []byte, err error) {
|
|
buf := make([]byte, maxOIDLength)
|
|
if _, err = readFull(r, buf[:1]); err != nil {
|
|
return
|
|
}
|
|
oidLen := buf[0]
|
|
if int(oidLen) > len(buf) {
|
|
err = errors.UnsupportedError("invalid oid length: " + strconv.Itoa(int(oidLen)))
|
|
return
|
|
}
|
|
oid = buf[:oidLen]
|
|
_, err = readFull(r, oid)
|
|
return
|
|
}
|
|
|
|
func (f *ecdsaKey) parse(r io.Reader) (err error) {
|
|
if f.oid, err = parseOID(r); err != nil {
|
|
return err
|
|
}
|
|
f.p.bytes, f.p.bitLength, err = readMPI(r)
|
|
return err
|
|
}
|
|
|
|
func (f *ecdsaKey) serialize(w io.Writer) (err error) {
|
|
buf := make([]byte, maxOIDLength+1)
|
|
buf[0] = byte(len(f.oid))
|
|
copy(buf[1:], f.oid)
|
|
if _, err = w.Write(buf[:len(f.oid)+1]); err != nil {
|
|
return
|
|
}
|
|
return writeMPIs(w, f.p)
|
|
}
|
|
|
|
func getCurveByOid(oid []byte) elliptic.Curve {
|
|
switch {
|
|
case bytes.Equal(oid, oidCurveP224):
|
|
return elliptic.P224()
|
|
case bytes.Equal(oid, oidCurveP256):
|
|
return elliptic.P256()
|
|
case bytes.Equal(oid, oidCurveP384):
|
|
return elliptic.P384()
|
|
case bytes.Equal(oid, oidCurveP521):
|
|
return elliptic.P521()
|
|
case bytes.Equal(oid, oidCurveP256r1):
|
|
return brainpool.P256r1()
|
|
case bytes.Equal(oid, oidCurveP384r1):
|
|
return brainpool.P384r1()
|
|
case bytes.Equal(oid, oidCurveP512r1):
|
|
return brainpool.P512r1()
|
|
case bytes.Equal(oid, oidCurve25519):
|
|
return curve25519.Cv25519()
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) {
|
|
var c = getCurveByOid(f.oid)
|
|
// Curve25519 should not be used in ECDSA.
|
|
if c == nil || bytes.Equal(f.oid, oidCurve25519) {
|
|
return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid))
|
|
}
|
|
// Note: Unmarshal already checks if point is on curve.
|
|
x, y := elliptic.Unmarshal(c, f.p.bytes)
|
|
if x == nil {
|
|
return nil, errors.UnsupportedError("failed to parse EC point")
|
|
}
|
|
return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil
|
|
}
|
|
|
|
func (f *ecdsaKey) newECDH() (*ecdh.PublicKey, error) {
|
|
var c = getCurveByOid(f.oid)
|
|
if c == nil {
|
|
return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid))
|
|
}
|
|
// ecdh.Unmarshal handles unmarshaling for all curve types. It
|
|
// also checks if point is on curve.
|
|
x, y := ecdh.Unmarshal(c, f.p.bytes)
|
|
if x == nil {
|
|
return nil, errors.UnsupportedError("failed to parse EC point")
|
|
}
|
|
return &ecdh.PublicKey{Curve: c, X: x, Y: y}, nil
|
|
}
|
|
|
|
func (f *ecdsaKey) byteLen() int {
|
|
return 1 + len(f.oid) + 2 + len(f.p.bytes)
|
|
}
|
|
|
|
type kdfHashFunction byte
|
|
type kdfAlgorithm byte
|
|
|
|
// ecdhKdf stores key derivation function parameters
|
|
// used for ECDH encryption. See RFC 6637, Section 9.
|
|
type ecdhKdf struct {
|
|
KdfHash kdfHashFunction
|
|
KdfAlgo kdfAlgorithm
|
|
}
|
|
|
|
func (f *ecdhKdf) parse(r io.Reader) (err error) {
|
|
buf := make([]byte, 1)
|
|
if _, err = readFull(r, buf); err != nil {
|
|
return
|
|
}
|
|
kdfLen := int(buf[0])
|
|
if kdfLen < 3 {
|
|
return errors.UnsupportedError("Unsupported ECDH KDF length: " + strconv.Itoa(kdfLen))
|
|
}
|
|
buf = make([]byte, kdfLen)
|
|
if _, err = readFull(r, buf); err != nil {
|
|
return
|
|
}
|
|
reserved := int(buf[0])
|
|
f.KdfHash = kdfHashFunction(buf[1])
|
|
f.KdfAlgo = kdfAlgorithm(buf[2])
|
|
if reserved != 0x01 {
|
|
return errors.UnsupportedError("Unsupported KDF reserved field: " + strconv.Itoa(reserved))
|
|
}
|
|
return
|
|
}
|
|
|
|
func (f *ecdhKdf) serialize(w io.Writer) (err error) {
|
|
buf := make([]byte, 4)
|
|
// See RFC 6637, Section 9, Algorithm-Specific Fields for ECDH keys.
|
|
buf[0] = byte(0x03) // Length of the following fields
|
|
buf[1] = byte(0x01) // Reserved for future extensions, must be 1 for now
|
|
buf[2] = byte(f.KdfHash)
|
|
buf[3] = byte(f.KdfAlgo)
|
|
_, err = w.Write(buf[:])
|
|
return
|
|
}
|
|
|
|
func (f *ecdhKdf) byteLen() int {
|
|
return 4
|
|
}
|
|
|
|
// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
|
|
type PublicKey struct {
|
|
CreationTime time.Time
|
|
PubKeyAlgo PublicKeyAlgorithm
|
|
PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey or *ecdsa.PublicKey
|
|
Fingerprint [20]byte
|
|
KeyId uint64
|
|
IsSubkey bool
|
|
|
|
n, e, p, q, g, y parsedMPI
|
|
|
|
// RFC 6637 fields
|
|
ec *ecdsaKey
|
|
ecdh *ecdhKdf
|
|
|
|
// EdDSA fields (no RFC available), uses ecdsa scaffolding
|
|
edk *edDSAkey
|
|
}
|
|
|
|
// signingKey provides a convenient abstraction over signature verification
|
|
// for v3 and v4 public keys.
|
|
type signingKey interface {
|
|
SerializeSignaturePrefix(io.Writer)
|
|
serializeWithoutHeaders(io.Writer) error
|
|
}
|
|
|
|
func FromBig(n *big.Int) parsedMPI {
|
|
return parsedMPI{
|
|
bytes: n.Bytes(),
|
|
bitLength: uint16(n.BitLen()),
|
|
}
|
|
}
|
|
|
|
func FromBytes(bytes []byte) parsedMPI {
|
|
return parsedMPI{
|
|
bytes: bytes,
|
|
bitLength: uint16(8 * len(bytes)),
|
|
}
|
|
}
|
|
|
|
// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
|
|
func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey {
|
|
pk := &PublicKey{
|
|
CreationTime: creationTime,
|
|
PubKeyAlgo: PubKeyAlgoRSA,
|
|
PublicKey: pub,
|
|
n: FromBig(pub.N),
|
|
e: FromBig(big.NewInt(int64(pub.E))),
|
|
}
|
|
|
|
pk.setFingerPrintAndKeyId()
|
|
return pk
|
|
}
|
|
|
|
// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey.
|
|
func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey {
|
|
pk := &PublicKey{
|
|
CreationTime: creationTime,
|
|
PubKeyAlgo: PubKeyAlgoDSA,
|
|
PublicKey: pub,
|
|
p: FromBig(pub.P),
|
|
q: FromBig(pub.Q),
|
|
g: FromBig(pub.G),
|
|
y: FromBig(pub.Y),
|
|
}
|
|
|
|
pk.setFingerPrintAndKeyId()
|
|
return pk
|
|
}
|
|
|
|
// check EdDSA public key material.
|
|
// There is currently no RFC for it, but it doesn't mean it's not
|
|
// implemented or in use.
|
|
func (e *edDSAkey) check() error {
|
|
if !bytes.Equal(e.oid, oidEdDSA) {
|
|
return errors.UnsupportedError(fmt.Sprintf("Bad OID for EdDSA key: %v", e.oid))
|
|
}
|
|
if bLen := len(e.p.bytes); bLen != 33 { // 32 bytes for ed25519 key and 1 byte for 0x40 header
|
|
return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA public key length: %d", bLen))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey.
|
|
func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey {
|
|
pk := &PublicKey{
|
|
CreationTime: creationTime,
|
|
PubKeyAlgo: PubKeyAlgoElGamal,
|
|
PublicKey: pub,
|
|
p: FromBig(pub.P),
|
|
g: FromBig(pub.G),
|
|
y: FromBig(pub.Y),
|
|
}
|
|
|
|
pk.setFingerPrintAndKeyId()
|
|
return pk
|
|
}
|
|
|
|
func getCurveOid(curve elliptic.Curve) (res []byte, err error) {
|
|
switch curve {
|
|
case elliptic.P224():
|
|
res = oidCurveP224
|
|
case elliptic.P256():
|
|
res = oidCurveP256
|
|
case elliptic.P384():
|
|
res = oidCurveP384
|
|
case elliptic.P521():
|
|
res = oidCurveP521
|
|
case brainpool.P256r1():
|
|
res = oidCurveP256r1
|
|
case brainpool.P384r1():
|
|
res = oidCurveP384r1
|
|
case brainpool.P512r1():
|
|
res = oidCurveP512r1
|
|
case curve25519.Cv25519():
|
|
res = oidCurve25519
|
|
default:
|
|
err = errors.UnsupportedError("unknown curve")
|
|
}
|
|
return
|
|
}
|
|
|
|
func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey {
|
|
pk := &PublicKey{
|
|
CreationTime: creationTime,
|
|
PubKeyAlgo: PubKeyAlgoECDSA,
|
|
PublicKey: pub,
|
|
ec: new(ecdsaKey),
|
|
}
|
|
oid, _ := getCurveOid(pub.Curve)
|
|
pk.ec.oid = oid
|
|
bs, bitLen := ecdh.Marshal(pub.Curve, pub.X, pub.Y)
|
|
pk.ec.p.bytes = bs
|
|
pk.ec.p.bitLength = uint16(bitLen)
|
|
|
|
pk.setFingerPrintAndKeyId()
|
|
return pk
|
|
}
|
|
|
|
func NewECDHPublicKey(creationTime time.Time, pub *ecdh.PublicKey) *PublicKey {
|
|
pk := &PublicKey{
|
|
CreationTime: creationTime,
|
|
PubKeyAlgo: PubKeyAlgoECDH,
|
|
PublicKey: pub,
|
|
ec: new(ecdsaKey),
|
|
}
|
|
oid, _ := getCurveOid(pub.Curve)
|
|
pk.ec.oid = oid
|
|
bs, bitLen := ecdh.Marshal(pub.Curve, pub.X, pub.Y)
|
|
pk.ec.p.bytes = bs
|
|
pk.ec.p.bitLength = uint16(bitLen)
|
|
|
|
hashbyte, _ := s2k.HashToHashId(crypto.SHA512)
|
|
pk.ecdh = &ecdhKdf{
|
|
KdfHash: kdfHashFunction(hashbyte),
|
|
KdfAlgo: kdfAlgorithm(CipherAES256),
|
|
}
|
|
|
|
pk.setFingerPrintAndKeyId()
|
|
return pk
|
|
}
|
|
|
|
func (pk *PublicKey) parse(r io.Reader) (err error) {
|
|
// RFC 4880, section 5.5.2
|
|
var buf [6]byte
|
|
_, err = readFull(r, buf[:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
if buf[0] != 4 {
|
|
return errors.UnsupportedError("public key version")
|
|
}
|
|
pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
|
|
pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
|
err = pk.parseRSA(r)
|
|
case PubKeyAlgoDSA:
|
|
err = pk.parseDSA(r)
|
|
case PubKeyAlgoElGamal:
|
|
err = pk.parseElGamal(r)
|
|
case PubKeyAlgoEdDSA:
|
|
pk.edk = new(edDSAkey)
|
|
if err = pk.edk.parse(r); err != nil {
|
|
return err
|
|
}
|
|
err = pk.edk.check()
|
|
case PubKeyAlgoECDSA:
|
|
pk.ec = new(ecdsaKey)
|
|
if err = pk.ec.parse(r); err != nil {
|
|
return err
|
|
}
|
|
pk.PublicKey, err = pk.ec.newECDSA()
|
|
case PubKeyAlgoECDH:
|
|
pk.ec = new(ecdsaKey)
|
|
if err = pk.ec.parse(r); err != nil {
|
|
return
|
|
}
|
|
pk.ecdh = new(ecdhKdf)
|
|
if err = pk.ecdh.parse(r); err != nil {
|
|
return
|
|
}
|
|
pk.PublicKey, err = pk.ec.newECDH()
|
|
case PubKeyAlgoBadElGamal:
|
|
// Key has ElGamal format but nil-implementation - it will
|
|
// load but it's not possible to do any operations using this
|
|
// key.
|
|
err = pk.parseElGamal(r)
|
|
if err != nil {
|
|
pk.PublicKey = nil
|
|
}
|
|
default:
|
|
err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
|
|
}
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
pk.setFingerPrintAndKeyId()
|
|
return
|
|
}
|
|
|
|
func (pk *PublicKey) setFingerPrintAndKeyId() {
|
|
// RFC 4880, section 12.2
|
|
fingerPrint := sha1.New()
|
|
pk.SerializeSignaturePrefix(fingerPrint)
|
|
pk.serializeWithoutHeaders(fingerPrint)
|
|
copy(pk.Fingerprint[:], fingerPrint.Sum(nil))
|
|
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
|
|
}
|
|
|
|
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
|
|
// section 5.5.2.
|
|
func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
|
|
pk.n.bytes, pk.n.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
pk.e.bytes, pk.e.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if len(pk.e.bytes) > 7 {
|
|
err = errors.UnsupportedError("large public exponent")
|
|
return
|
|
}
|
|
rsa := &rsa.PublicKey{
|
|
N: new(big.Int).SetBytes(pk.n.bytes),
|
|
E: 0,
|
|
}
|
|
// Warning: incompatibility with crypto/rsa: keybase fork uses
|
|
// int64 public exponents instead of int32.
|
|
for i := 0; i < len(pk.e.bytes); i++ {
|
|
rsa.E <<= 8
|
|
rsa.E |= int64(pk.e.bytes[i])
|
|
}
|
|
pk.PublicKey = rsa
|
|
return
|
|
}
|
|
|
|
// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
|
|
// section 5.5.2.
|
|
func (pk *PublicKey) parseDSA(r io.Reader) (err error) {
|
|
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
pk.q.bytes, pk.q.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
dsa := new(dsa.PublicKey)
|
|
dsa.P = new(big.Int).SetBytes(pk.p.bytes)
|
|
dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
|
|
dsa.G = new(big.Int).SetBytes(pk.g.bytes)
|
|
dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
|
|
pk.PublicKey = dsa
|
|
return
|
|
}
|
|
|
|
// parseElGamal parses ElGamal public key material from the given Reader. See
|
|
// RFC 4880, section 5.5.2.
|
|
func (pk *PublicKey) parseElGamal(r io.Reader) (err error) {
|
|
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
pk.g.bytes, pk.g.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
pk.y.bytes, pk.y.bitLength, err = readMPI(r)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
elgamal := new(elgamal.PublicKey)
|
|
elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
|
|
elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
|
|
elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
|
|
pk.PublicKey = elgamal
|
|
return
|
|
}
|
|
|
|
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
|
|
// The prefix is used when calculating a signature over this public key. See
|
|
// RFC 4880, section 5.2.4.
|
|
func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) {
|
|
var pLength uint16
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
|
pLength += 2 + uint16(len(pk.n.bytes))
|
|
pLength += 2 + uint16(len(pk.e.bytes))
|
|
case PubKeyAlgoDSA:
|
|
pLength += 2 + uint16(len(pk.p.bytes))
|
|
pLength += 2 + uint16(len(pk.q.bytes))
|
|
pLength += 2 + uint16(len(pk.g.bytes))
|
|
pLength += 2 + uint16(len(pk.y.bytes))
|
|
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
|
|
pLength += 2 + uint16(len(pk.p.bytes))
|
|
pLength += 2 + uint16(len(pk.g.bytes))
|
|
pLength += 2 + uint16(len(pk.y.bytes))
|
|
case PubKeyAlgoECDSA:
|
|
pLength += uint16(pk.ec.byteLen())
|
|
case PubKeyAlgoECDH:
|
|
pLength += uint16(pk.ec.byteLen())
|
|
pLength += uint16(pk.ecdh.byteLen())
|
|
case PubKeyAlgoEdDSA:
|
|
pLength += uint16(pk.edk.byteLen())
|
|
default:
|
|
panic("unknown public key algorithm")
|
|
}
|
|
pLength += 6
|
|
h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
|
|
return
|
|
}
|
|
|
|
func (pk *PublicKey) Serialize(w io.Writer) (err error) {
|
|
length := 6 // 6 byte header
|
|
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
|
length += 2 + len(pk.n.bytes)
|
|
length += 2 + len(pk.e.bytes)
|
|
case PubKeyAlgoDSA:
|
|
length += 2 + len(pk.p.bytes)
|
|
length += 2 + len(pk.q.bytes)
|
|
length += 2 + len(pk.g.bytes)
|
|
length += 2 + len(pk.y.bytes)
|
|
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
|
|
length += 2 + len(pk.p.bytes)
|
|
length += 2 + len(pk.g.bytes)
|
|
length += 2 + len(pk.y.bytes)
|
|
case PubKeyAlgoECDSA:
|
|
length += pk.ec.byteLen()
|
|
case PubKeyAlgoECDH:
|
|
length += pk.ec.byteLen()
|
|
length += pk.ecdh.byteLen()
|
|
case PubKeyAlgoEdDSA:
|
|
length += pk.edk.byteLen()
|
|
default:
|
|
panic("unknown public key algorithm")
|
|
}
|
|
|
|
packetType := packetTypePublicKey
|
|
if pk.IsSubkey {
|
|
packetType = packetTypePublicSubkey
|
|
}
|
|
err = serializeHeader(w, packetType, length)
|
|
if err != nil {
|
|
return
|
|
}
|
|
return pk.serializeWithoutHeaders(w)
|
|
}
|
|
|
|
// serializeWithoutHeaders marshals the PublicKey to w in the form of an
|
|
// OpenPGP public key packet, not including the packet header.
|
|
func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
|
|
var buf [6]byte
|
|
buf[0] = 4
|
|
t := uint32(pk.CreationTime.Unix())
|
|
buf[1] = byte(t >> 24)
|
|
buf[2] = byte(t >> 16)
|
|
buf[3] = byte(t >> 8)
|
|
buf[4] = byte(t)
|
|
buf[5] = byte(pk.PubKeyAlgo)
|
|
|
|
_, err = w.Write(buf[:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
|
return writeMPIs(w, pk.n, pk.e)
|
|
case PubKeyAlgoDSA:
|
|
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
|
|
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
|
|
return writeMPIs(w, pk.p, pk.g, pk.y)
|
|
case PubKeyAlgoECDSA:
|
|
return pk.ec.serialize(w)
|
|
case PubKeyAlgoEdDSA:
|
|
return pk.edk.serialize(w)
|
|
case PubKeyAlgoECDH:
|
|
if err = pk.ec.serialize(w); err != nil {
|
|
return
|
|
}
|
|
return pk.ecdh.serialize(w)
|
|
}
|
|
return errors.InvalidArgumentError("bad public-key algorithm")
|
|
}
|
|
|
|
// CanSign returns true iff this public key can generate signatures
|
|
func (pk *PublicKey) CanSign() bool {
|
|
return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
|
|
}
|
|
|
|
// VerifySignature returns nil iff sig is a valid signature, made by this
|
|
// public key, of the data hashed into signed. signed is mutated by this call.
|
|
func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
|
|
if !pk.CanSign() {
|
|
return errors.InvalidArgumentError("public key cannot generate signatures")
|
|
}
|
|
|
|
signed.Write(sig.HashSuffix)
|
|
hashBytes := signed.Sum(nil)
|
|
|
|
// NOTE(maxtaco) 2016-08-22
|
|
//
|
|
// We used to do this:
|
|
//
|
|
// if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
|
|
// return errors.SignatureError("hash tag doesn't match")
|
|
// }
|
|
//
|
|
// But don't do anything in this case. Some GPGs generate bad
|
|
// 2-byte hash prefixes, but GPG also doesn't seem to care on
|
|
// import. See BrentMaxwell's key. I think it's safe to disable
|
|
// this check!
|
|
|
|
if pk.PubKeyAlgo != sig.PubKeyAlgo {
|
|
return errors.InvalidArgumentError("public key and signature use different algorithms")
|
|
}
|
|
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
|
|
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
|
|
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes))
|
|
if err != nil {
|
|
return errors.SignatureError("RSA verification failure")
|
|
}
|
|
return nil
|
|
case PubKeyAlgoDSA:
|
|
dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
|
|
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
|
|
subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
|
|
if len(hashBytes) > subgroupSize {
|
|
hashBytes = hashBytes[:subgroupSize]
|
|
}
|
|
if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
|
|
return errors.SignatureError("DSA verification failure")
|
|
}
|
|
return nil
|
|
case PubKeyAlgoECDSA:
|
|
ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey)
|
|
if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.bytes), new(big.Int).SetBytes(sig.ECDSASigS.bytes)) {
|
|
return errors.SignatureError("ECDSA verification failure")
|
|
}
|
|
return nil
|
|
case PubKeyAlgoEdDSA:
|
|
if !pk.edk.Verify(hashBytes, sig.EdDSASigR, sig.EdDSASigS) {
|
|
return errors.SignatureError("EdDSA verification failure")
|
|
}
|
|
return nil
|
|
default:
|
|
return errors.SignatureError("Unsupported public key algorithm used in signature")
|
|
}
|
|
panic("unreachable")
|
|
}
|
|
|
|
// VerifySignatureV3 returns nil iff sig is a valid signature, made by this
|
|
// public key, of the data hashed into signed. signed is mutated by this call.
|
|
func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) {
|
|
if !pk.CanSign() {
|
|
return errors.InvalidArgumentError("public key cannot generate signatures")
|
|
}
|
|
|
|
suffix := make([]byte, 5)
|
|
suffix[0] = byte(sig.SigType)
|
|
binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix()))
|
|
signed.Write(suffix)
|
|
hashBytes := signed.Sum(nil)
|
|
|
|
if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
|
|
return errors.SignatureError("hash tag doesn't match")
|
|
}
|
|
|
|
if pk.PubKeyAlgo != sig.PubKeyAlgo {
|
|
return errors.InvalidArgumentError("public key and signature use different algorithms")
|
|
}
|
|
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
|
|
rsaPublicKey := pk.PublicKey.(*rsa.PublicKey)
|
|
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil {
|
|
return errors.SignatureError("RSA verification failure")
|
|
}
|
|
return
|
|
case PubKeyAlgoDSA:
|
|
dsaPublicKey := pk.PublicKey.(*dsa.PublicKey)
|
|
// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
|
|
subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
|
|
if len(hashBytes) > subgroupSize {
|
|
hashBytes = hashBytes[:subgroupSize]
|
|
}
|
|
if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
|
|
return errors.SignatureError("DSA verification failure")
|
|
}
|
|
return nil
|
|
default:
|
|
panic("shouldn't happen")
|
|
}
|
|
panic("unreachable")
|
|
}
|
|
|
|
// keySignatureHash returns a Hash of the message that needs to be signed for
|
|
// pk to assert a subkey relationship to signed.
|
|
func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
|
|
if !hashFunc.Available() {
|
|
return nil, errors.UnsupportedError("hash function")
|
|
}
|
|
h = hashFunc.New()
|
|
|
|
updateKeySignatureHash(pk, signed, h)
|
|
|
|
return
|
|
}
|
|
|
|
// updateKeySignatureHash does the actual hash updates for keySignatureHash.
|
|
func updateKeySignatureHash(pk, signed signingKey, h hash.Hash) {
|
|
// RFC 4880, section 5.2.4
|
|
pk.SerializeSignaturePrefix(h)
|
|
pk.serializeWithoutHeaders(h)
|
|
signed.SerializeSignaturePrefix(h)
|
|
signed.serializeWithoutHeaders(h)
|
|
}
|
|
|
|
// VerifyKeySignature returns nil iff sig is a valid signature, made by this
|
|
// public key, of signed.
|
|
func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error {
|
|
h, err := keySignatureHash(pk, signed, sig.Hash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = pk.VerifySignature(h, sig); err != nil {
|
|
return err
|
|
}
|
|
|
|
if sig.FlagSign {
|
|
|
|
// BUG(maxtaco)
|
|
//
|
|
// We should check for more than FlagsSign here, because if
|
|
// you read keys.go, we can sometimes use signing subkeys even if they're
|
|
// not explicitly flagged as such. However, so doing fails lots of currently
|
|
// working tests, so I'm not going to do much here.
|
|
//
|
|
// In other words, we should have this disjunction in the condition above:
|
|
//
|
|
// || (!sig.FlagsValid && pk.PubKeyAlgo.CanSign()) {
|
|
//
|
|
|
|
// Signing subkeys must be cross-signed. See
|
|
// https://www.gnupg.org/faq/subkey-cross-certify.html.
|
|
if sig.EmbeddedSignature == nil {
|
|
return errors.StructuralError("signing subkey is missing cross-signature")
|
|
}
|
|
// Verify the cross-signature. This is calculated over the same
|
|
// data as the main signature, so we cannot just recursively
|
|
// call signed.VerifyKeySignature(...)
|
|
if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil {
|
|
return errors.StructuralError("error while hashing for cross-signature: " + err.Error())
|
|
}
|
|
if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil {
|
|
return errors.StructuralError("error while verifying cross-signature: " + err.Error())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
|
|
if !hashFunc.Available() {
|
|
return nil, errors.UnsupportedError("hash function")
|
|
}
|
|
h = hashFunc.New()
|
|
|
|
// RFC 4880, section 5.2.4
|
|
pk.SerializeSignaturePrefix(h)
|
|
pk.serializeWithoutHeaders(h)
|
|
|
|
return
|
|
}
|
|
|
|
// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this
|
|
// public key.
|
|
func (pk *PublicKey) VerifyRevocationSignature(revokedKey *PublicKey, sig *Signature) (err error) {
|
|
h, err := keyRevocationHash(revokedKey, sig.Hash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return pk.VerifySignature(h, sig)
|
|
}
|
|
|
|
type teeHash struct {
|
|
h hash.Hash
|
|
}
|
|
|
|
func (t teeHash) Write(b []byte) (n int, err error) {
|
|
fmt.Printf("hash -> %s %+v\n", string(b), b)
|
|
return t.h.Write(b)
|
|
}
|
|
func (t teeHash) Sum(b []byte) []byte { return t.h.Sum(b) }
|
|
func (t teeHash) Reset() { t.h.Reset() }
|
|
func (t teeHash) Size() int { return t.h.Size() }
|
|
func (t teeHash) BlockSize() int { return t.h.BlockSize() }
|
|
|
|
// userIdSignatureHash returns a Hash of the message that needs to be signed
|
|
// to assert that pk is a valid key for id.
|
|
func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
|
|
if !hashFunc.Available() {
|
|
return nil, errors.UnsupportedError("hash function")
|
|
}
|
|
h = hashFunc.New()
|
|
|
|
updateUserIdSignatureHash(id, pk, h)
|
|
|
|
return
|
|
}
|
|
|
|
// updateUserIdSignatureHash does the actual hash updates for
|
|
// userIdSignatureHash.
|
|
func updateUserIdSignatureHash(id string, pk *PublicKey, h hash.Hash) {
|
|
// RFC 4880, section 5.2.4
|
|
pk.SerializeSignaturePrefix(h)
|
|
pk.serializeWithoutHeaders(h)
|
|
|
|
var buf [5]byte
|
|
buf[0] = 0xb4
|
|
buf[1] = byte(len(id) >> 24)
|
|
buf[2] = byte(len(id) >> 16)
|
|
buf[3] = byte(len(id) >> 8)
|
|
buf[4] = byte(len(id))
|
|
h.Write(buf[:])
|
|
h.Write([]byte(id))
|
|
|
|
return
|
|
}
|
|
|
|
// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
|
|
// public key, that id is the identity of pub.
|
|
func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) {
|
|
h, err := userIdSignatureHash(id, pub, sig.Hash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return pk.VerifySignature(h, sig)
|
|
}
|
|
|
|
// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this
|
|
// public key, that id is the identity of pub.
|
|
func (pk *PublicKey) VerifyUserIdSignatureV3(id string, pub *PublicKey, sig *SignatureV3) (err error) {
|
|
h, err := userIdSignatureV3Hash(id, pub, sig.Hash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return pk.VerifySignatureV3(h, sig)
|
|
}
|
|
|
|
// KeyIdString returns the public key's fingerprint in capital hex
|
|
// (e.g. "6C7EE1B8621CC013").
|
|
func (pk *PublicKey) KeyIdString() string {
|
|
return fmt.Sprintf("%X", pk.Fingerprint[12:20])
|
|
}
|
|
|
|
// KeyIdShortString returns the short form of public key's fingerprint
|
|
// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
|
|
func (pk *PublicKey) KeyIdShortString() string {
|
|
return fmt.Sprintf("%X", pk.Fingerprint[16:20])
|
|
}
|
|
|
|
// A parsedMPI is used to store the contents of a big integer, along with the
|
|
// bit length that was specified in the original input. This allows the MPI to
|
|
// be reserialized exactly.
|
|
type parsedMPI struct {
|
|
bytes []byte
|
|
bitLength uint16
|
|
}
|
|
|
|
// writeMPIs is a utility function for serializing several big integers to the
|
|
// given Writer.
|
|
func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) {
|
|
for _, mpi := range mpis {
|
|
err = writeMPI(w, mpi.bitLength, mpi.bytes)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// BitLength returns the bit length for the given public key. Used for
|
|
// displaying key information, actual buffers and BigInts inside may
|
|
// have non-matching different size if the key is invalid.
|
|
func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
|
|
bitLength = pk.n.bitLength
|
|
case PubKeyAlgoDSA:
|
|
bitLength = pk.p.bitLength
|
|
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
|
|
bitLength = pk.p.bitLength
|
|
case PubKeyAlgoECDH:
|
|
ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey)
|
|
bitLength = uint16(ecdhPublicKey.Curve.Params().BitSize)
|
|
case PubKeyAlgoECDSA:
|
|
ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey)
|
|
bitLength = uint16(ecdsaPublicKey.Curve.Params().BitSize)
|
|
case PubKeyAlgoEdDSA:
|
|
// EdDSA only support ed25519 curves right now, just return
|
|
// the length. Also, we don't have any PublicKey.Curve object
|
|
// to look the size up from.
|
|
bitLength = 256
|
|
default:
|
|
err = errors.InvalidArgumentError("bad public-key algorithm")
|
|
}
|
|
return
|
|
}
|
|
|
|
func (pk *PublicKey) ErrorIfDeprecated() error {
|
|
switch pk.PubKeyAlgo {
|
|
case PubKeyAlgoBadElGamal:
|
|
return errors.DeprecatedKeyError("ElGamal Encrypt or Sign (algo 20) is deprecated")
|
|
default:
|
|
return nil
|
|
}
|
|
}
|