994 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			994 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| // 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()
 | |
| 		if err == nil {
 | |
| 			pk.PublicKey = ed25519.PublicKey(pk.edk.p.bytes[1:])
 | |
| 		}
 | |
| 	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
 | |
| 	}
 | |
| }
 |