1
0
Fork 0
forked from forgejo/forgejo

update vendor keybase/go-crypto (#10234)

This commit is contained in:
6543 2020-02-11 19:58:23 +01:00 committed by GitHub
parent 86fdba177a
commit bfd62b6f01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1062 additions and 769 deletions

View file

@ -10,6 +10,7 @@ import (
"bufio"
"bytes"
"encoding/base64"
"fmt"
"io"
"strings"
"unicode"
@ -89,50 +90,114 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
return
}
line, _, err := l.in.ReadLine()
line, isPrefix, err := l.in.ReadLine()
if err != nil {
return
}
// Entry-level cleanup, just trim spaces.
line = bytes.TrimFunc(line, ourIsSpace)
if len(line) == 5 && line[0] == '=' {
// This is the checksum line
lineWithChecksum := false
foldedChecksum := false
if !isPrefix && len(line) >= 5 && line[len(line)-5] == '=' && line[len(line)-4] != '=' {
// This is the checksum line. Checksum should appear on separate line,
// but some bundles don't have a newline between main payload and the
// checksum, and we try to support that.
// `=` is not a base64 character with the exception of padding, and the
// padding can only be 2 characters long at most ("=="), so we can
// safely assume that 5 characters starting with `=` at the end of the
// line can't be a valid ending of a base64 stream. In other words, `=`
// at position len-5 in base64 stream can never be a valid part of that
// stream.
// Checksum can never appear if isPrefix is true - that is, when
// ReadLine returned non-final part of some line because it was longer
// than its buffer.
if l.crc != nil {
// Error out early if there are multiple checksums.
return 0, ArmorCorrupt
}
var expectedBytes [3]byte
var m int
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
if m != 3 || err != nil {
return
m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[len(line)-4:])
if err != nil {
return 0, fmt.Errorf("error decoding CRC: %s", err.Error())
} else if m != 3 {
return 0, fmt.Errorf("error decoding CRC: wrong size CRC")
}
crc := uint32(expectedBytes[0])<<16 |
uint32(expectedBytes[1])<<8 |
uint32(expectedBytes[2])
l.crc = &crc
line = line[:len(line)-5]
lineWithChecksum = true
// If we've found a checksum but there is still data left, we don't
// want to enter the "looking for armor end" loop, we still need to
// return the leftover data to the reader.
foldedChecksum = len(line) > 0
// At this point, `line` contains leftover data or "" (if checksum
// was on separate line.)
}
expectArmorEnd := false
if l.crc != nil && !foldedChecksum {
// "looking for armor end" loop
// We have a checksum, and we are now reading what comes afterwards.
// Skip all empty lines until we see something and we except it to be
// ArmorEnd at this point.
// This loop is not entered if there is more data *before* the CRC
// suffix (if the CRC is not on separate line).
for {
line, _, err = l.in.ReadLine()
if err != nil && err != io.EOF {
return
}
if len(strings.TrimSpace(string(line))) > 0 {
break
}
lineWithChecksum = false
line, _, err = l.in.ReadLine()
if err == io.EOF {
break
}
if err != nil {
return
}
}
if !bytes.HasPrefix(line, armorEnd) {
return 0, ArmorCorrupt
}
l.eof = true
return 0, io.EOF
expectArmorEnd = true
}
if bytes.HasPrefix(line, armorEnd) {
// Unexpected ending, there was no checksum.
if lineWithChecksum {
// ArmorEnd and checksum at the same line?
return 0, ArmorCorrupt
}
l.eof = true
l.crc = nil
return 0, io.EOF
} else if expectArmorEnd {
// We wanted armorEnd but didn't see one.
return 0, ArmorCorrupt
}
// Clean-up line from whitespace to pass it further (to base64
// decoder). This is done after test for CRC and test for
// armorEnd. Keys that have whitespace in CRC will have CRC
// treated as part of the payload and probably fail in base64
// reading.
line = bytes.Map(func(r rune) rune {
if ourIsSpace(r) {
return -1
}
return r
}, line)
n = copy(p, line)
bytesToSave := len(line) - n
if bytesToSave > 0 {

View file

@ -280,3 +280,37 @@ func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) {
return elliptic.Unmarshal(curve, data)
}
func GenerateKey(curve elliptic.Curve, random io.Reader) (priv *PrivateKey, err error) {
var privBytes []byte
var Vx, Vy *big.Int
if _, ok := curve25519.ToCurve25519(curve); ok {
privBytes = make([]byte, 32)
_, err = io.ReadFull(random, privBytes)
if err != nil {
return nil, err
}
// NOTE: PGP expect scalars in reverse order than Curve 25519
// go library. That's why this trimming is backwards compared
// to curve25519.go
privBytes[31] &= 248
privBytes[0] &= 127
privBytes[0] |= 64
Vx,Vy = curve.ScalarBaseMult(privBytes)
} else {
privBytes, Vx, Vy, err = elliptic.GenerateKey(curve, random)
if err != nil {
return nil, err
}
}
priv = &PrivateKey{}
priv.X = new(big.Int).SetBytes(privBytes)
priv.PublicKey.Curve = curve
priv.PublicKey.X = Vx
priv.PublicKey.Y = Vy
return priv, nil
}

View file

@ -70,3 +70,11 @@ type UnknownPacketTypeError uint8
func (upte UnknownPacketTypeError) Error() string {
return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
}
// DeprecatedKeyError indicates that the key was read and verified
// properly, but uses a deprecated algorithm and can't be used.
type DeprecatedKeyError string
func (d DeprecatedKeyError) Error() string {
return "openpgp: key is deprecated: " + string(d)
}

View file

@ -118,7 +118,8 @@ func (e *Entity) primaryIdentity() *Identity {
func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
candidateSubkey := -1
// Iterate the keys to find the newest key
// Iterate the keys to find the newest, non-revoked key that can
// encrypt.
var maxTime time.Time
for i, subkey := range e.Subkeys {
@ -172,13 +173,18 @@ func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
func (e *Entity) signingKey(now time.Time) (Key, bool) {
candidateSubkey := -1
// Iterate the keys to find the newest, non-revoked key that can
// sign.
var maxTime time.Time
for i, subkey := range e.Subkeys {
if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) &&
subkey.PrivateKey.PrivateKey != nil &&
subkey.PublicKey.PubKeyAlgo.CanSign() &&
!subkey.Sig.KeyExpired(now) &&
subkey.Revocation == nil &&
!subkey.Sig.KeyExpired(now) {
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
candidateSubkey = i
maxTime = subkey.Sig.CreationTime
break
}
}
@ -504,7 +510,7 @@ EachPacket:
// Only register an identity once we've gotten a valid self-signature.
// It's possible therefore for us to throw away `current` in the case
// no valid self-signatures were found. That's OK as long as there are
// other identies that make sense.
// other identities that make sense.
//
// NOTE! We might later see a revocation for this very same UID, and it
// won't be undone. We've preserved this feature from the original
@ -645,6 +651,15 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p
}
}
}
if subKey.Sig != nil {
if err := subKey.PublicKey.ErrorIfDeprecated(); err != nil {
// Key passed signature check but is deprecated.
subKey.Sig = nil
lastErr = err
}
}
if subKey.Sig != nil {
e.Subkeys = append(e.Subkeys, subKey)
} else {
@ -690,7 +705,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
}
isPrimaryId := true
e.Identities[uid.Id] = &Identity{
Name: uid.Name,
Name: uid.Id,
UserId: uid,
SelfSignature: &packet.Signature{
CreationTime: currentTime,
@ -705,6 +720,17 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
},
}
// If the user passes in a DefaultHash via packet.Config, set the
// PreferredHash for the SelfSignature.
if config != nil && config.DefaultHash != 0 {
e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)}
}
// Likewise for DefaultCipher.
if config != nil && config.DefaultCipher != 0 {
e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)}
}
e.Subkeys = make([]Subkey, 1)
e.Subkeys[0] = Subkey{
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
@ -756,10 +782,16 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error
if err != nil {
return
}
// Workaround shortcoming of SignKey(), which doesn't work to reverse-sign
// sub-signing keys. So if requested, just reuse the signatures already
// available to us (if we read this key from a keyring).
if e.PrivateKey.PrivateKey != nil && !config.ReuseSignatures() {
// If not reusing existing signatures, sign subkey using private key
// (subkey binding), but also sign primary key using subkey (primary
// key binding) if subkey is used for signing.
if subkey.Sig.FlagSign {
err = subkey.Sig.CrossSignKey(e.PrimaryKey, subkey.PrivateKey, config)
if err != nil {
return err
}
}
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
if err != nil {
return

View file

@ -83,6 +83,10 @@ func checksumKeyMaterial(key []byte) uint16 {
// private key must have been decrypted first.
// If config is nil, sensible defaults will be used.
func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
if priv == nil || priv.PrivateKey == nil {
return errors.InvalidArgumentError("attempting to decrypt with nil PrivateKey")
}
var err error
var b []byte
@ -90,7 +94,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
// padding oracle attacks.
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes)
k := priv.PrivateKey.(*rsa.PrivateKey)
b, err = rsa.DecryptPKCS1v15(config.Random(), k, padToKeySize(&k.PublicKey, e.encryptedMPI1.bytes))
case PubKeyAlgoElGamal:
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)

View file

@ -17,6 +17,7 @@ import (
"github.com/keybase/go-crypto/cast5"
"github.com/keybase/go-crypto/openpgp/errors"
"github.com/keybase/go-crypto/rsa"
)
// readFull is the same as io.ReadFull except that reading zero bytes returns
@ -413,10 +414,12 @@ const (
PubKeyAlgoElGamal PublicKeyAlgorithm = 16
PubKeyAlgoDSA PublicKeyAlgorithm = 17
// RFC 6637, Section 5.
PubKeyAlgoECDH PublicKeyAlgorithm = 18
PubKeyAlgoECDSA PublicKeyAlgorithm = 19
PubKeyAlgoECDH PublicKeyAlgorithm = 18
PubKeyAlgoECDSA PublicKeyAlgorithm = 19
PubKeyAlgoBadElGamal PublicKeyAlgorithm = 20 // Reserved (deprecated, formerly ElGamal Encrypt or Sign)
// RFC -1
PubKeyAlgoEdDSA PublicKeyAlgorithm = 22
PubKeyAlgoEdDSA PublicKeyAlgorithm = 22
)
// CanEncrypt returns true if it's possible to encrypt a message to a public
@ -507,19 +510,17 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) {
numBytes := (int(bitLength) + 7) / 8
mpi = make([]byte, numBytes)
_, err = readFull(r, mpi)
return
}
// mpiLength returns the length of the given *big.Int when serialized as an
// MPI.
func mpiLength(n *big.Int) (mpiLengthInBytes int) {
mpiLengthInBytes = 2 /* MPI length */
mpiLengthInBytes += (n.BitLen() + 7) / 8
// According to RFC 4880 3.2. we should check that the MPI has no leading
// zeroes (at least when not an encrypted MPI?), but this implementation
// does generate leading zeroes, so we keep accepting them.
return
}
// writeMPI serializes a big integer to w.
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) {
// Note that we can produce leading zeroes, in violation of RFC 4880 3.2.
// Implementations seem to be tolerant of them, and stripping them would
// make it complex to guarantee matching re-serialization.
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
if err == nil {
_, err = w.Write(mpiBytes)
@ -551,6 +552,18 @@ func writeBig(w io.Writer, i *big.Int) error {
return writeMPI(w, uint16(i.BitLen()), i.Bytes())
}
// padToKeySize left-pads a MPI with zeroes to match the length of the
// specified RSA public.
func padToKeySize(pub *rsa.PublicKey, b []byte) []byte {
k := (pub.N.BitLen() + 7) / 8
if len(b) >= k {
return b
}
bb := make([]byte, k)
copy(bb[len(bb)-len(b):], b)
return bb
}
// CompressionAlgo Represents the different compression algorithms
// supported by OpenPGP (except for BZIP2, which is not currently
// supported). See Section 9.3 of RFC 4880.

View file

@ -44,6 +44,10 @@ type EdDSAPrivateKey struct {
seed parsedMPI
}
func (e *EdDSAPrivateKey) Seed() []byte {
return e.seed.bytes
}
func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) {
r := bytes.NewReader(e.seed.bytes)
publicKey, privateKey, err := ed25519.GenerateKey(r)
@ -89,6 +93,13 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK
return pk
}
func NewECDHPrivateKey(currentTime time.Time, priv *ecdh.PrivateKey) *PrivateKey {
pk := new(PrivateKey)
pk.PublicKey = *NewECDHPublicKey(currentTime, &priv.PublicKey)
pk.PrivateKey = priv
return pk
}
func (pk *PrivateKey) parse(r io.Reader) (err error) {
err = (&pk.PublicKey).parse(r)
if err != nil {
@ -415,8 +426,11 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
return pk.parseECDHPrivateKey(data)
case PubKeyAlgoEdDSA:
return pk.parseEdDSAPrivateKey(data)
case PubKeyAlgoBadElGamal:
return errors.UnsupportedError("parsing el-gamal sign-or-encrypt privatekeys is unsupported")
default:
return errors.UnsupportedError("cannot parse this private key type")
}
panic("impossible")
}
func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) {

View file

@ -27,10 +27,13 @@ import (
"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
@ -128,6 +131,8 @@ func (f *ecdsaKey) serialize(w io.Writer) (err error) {
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):
@ -324,6 +329,30 @@ func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *Public
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,
@ -331,22 +360,34 @@ func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey
PublicKey: pub,
ec: new(ecdsaKey),
}
switch pub.Curve {
case elliptic.P256():
pk.ec.oid = oidCurveP256
case elliptic.P384():
pk.ec.oid = oidCurveP384
case elliptic.P521():
pk.ec.oid = oidCurveP521
case brainpool.P256r1():
pk.ec.oid = oidCurveP256r1
case brainpool.P384r1():
pk.ec.oid = oidCurveP384r1
case brainpool.P512r1():
pk.ec.oid = oidCurveP512r1
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.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes))
pk.setFingerPrintAndKeyId()
return pk
@ -377,6 +418,9 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
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 {
@ -393,6 +437,14 @@ func (pk *PublicKey) parse(r io.Reader) (err error) {
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)))
}
@ -433,6 +485,8 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
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])
@ -508,7 +562,7 @@ func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) {
pLength += 2 + uint16(len(pk.q.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
case PubKeyAlgoElGamal:
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
pLength += 2 + uint16(len(pk.p.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
@ -539,7 +593,7 @@ func (pk *PublicKey) Serialize(w io.Writer) (err error) {
length += 2 + len(pk.q.bytes)
length += 2 + len(pk.g.bytes)
length += 2 + len(pk.y.bytes)
case PubKeyAlgoElGamal:
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
length += 2 + len(pk.p.bytes)
length += 2 + len(pk.g.bytes)
length += 2 + len(pk.y.bytes)
@ -587,7 +641,7 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
return writeMPIs(w, pk.n, pk.e)
case PubKeyAlgoDSA:
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
case PubKeyAlgoElGamal:
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
return writeMPIs(w, pk.p, pk.g, pk.y)
case PubKeyAlgoECDSA:
return pk.ec.serialize(w)
@ -637,7 +691,7 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes))
if err != nil {
return errors.SignatureError("RSA verification failure")
}
@ -694,7 +748,7 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
rsaPublicKey := pk.PublicKey.(*rsa.PublicKey)
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil {
if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil {
return errors.SignatureError("RSA verification failure")
}
return
@ -910,7 +964,7 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
bitLength = pk.n.bitLength
case PubKeyAlgoDSA:
bitLength = pk.p.bitLength
case PubKeyAlgoElGamal:
case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal:
bitLength = pk.p.bitLength
case PubKeyAlgoECDH:
ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey)
@ -928,3 +982,12 @@ func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
}
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
}
}

View file

@ -105,6 +105,8 @@ func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) {
return
}
rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)}
// 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])

View file

@ -10,6 +10,7 @@ import (
"crypto/dsa"
"crypto/ecdsa"
"encoding/binary"
"fmt"
"hash"
"io"
"strconv"
@ -384,18 +385,20 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
err = errors.StructuralError("empty key flags subpacket")
return
}
sig.FlagsValid = true
if subpacket[0]&KeyFlagCertify != 0 {
sig.FlagCertify = true
}
if subpacket[0]&KeyFlagSign != 0 {
sig.FlagSign = true
}
if subpacket[0]&KeyFlagEncryptCommunications != 0 {
sig.FlagEncryptCommunications = true
}
if subpacket[0]&KeyFlagEncryptStorage != 0 {
sig.FlagEncryptStorage = true
if subpacket[0] != 0 {
sig.FlagsValid = true
if subpacket[0]&KeyFlagCertify != 0 {
sig.FlagCertify = true
}
if subpacket[0]&KeyFlagSign != 0 {
sig.FlagSign = true
}
if subpacket[0]&KeyFlagEncryptCommunications != 0 {
sig.FlagEncryptCommunications = true
}
if subpacket[0]&KeyFlagEncryptStorage != 0 {
sig.FlagEncryptStorage = true
}
}
case reasonForRevocationSubpacket:
// Reason For Revocation, section 5.2.3.23
@ -624,6 +627,13 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
return
}
// Parameter check, if this is wrong we will make a signature but
// not serialize it later.
if sig.PubKeyAlgo != priv.PubKeyAlgo {
err = errors.InvalidArgumentError("signature pub key algo does not match priv key")
return
}
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
@ -637,26 +647,29 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e
digest = digest[:subgroupSize]
}
r, s, err := dsa.Sign(config.Random(), dsaPriv, digest)
if err == nil {
sig.DSASigR.bytes = r.Bytes()
sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
sig.DSASigS.bytes = s.Bytes()
sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
if err != nil {
return err
}
sig.DSASigR.bytes = r.Bytes()
sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
sig.DSASigS.bytes = s.Bytes()
sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
case PubKeyAlgoECDSA:
r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest)
if err == nil {
sig.ECDSASigR = FromBig(r)
sig.ECDSASigS = FromBig(s)
if err != nil {
return err
}
sig.ECDSASigR = FromBig(r)
sig.ECDSASigS = FromBig(s)
case PubKeyAlgoEdDSA:
r, s, err := priv.PrivateKey.(*EdDSAPrivateKey).Sign(digest)
if err == nil {
sig.EdDSASigR = FromBytes(r)
sig.EdDSASigS = FromBytes(s)
if err != nil {
return err
}
sig.EdDSASigR = FromBytes(r)
sig.EdDSASigS = FromBytes(s)
default:
err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
err = errors.UnsupportedError("public key algorithm for signing: " + strconv.Itoa(int(priv.PubKeyAlgo)))
}
return
@ -704,6 +717,28 @@ func (sig *Signature) SignKeyWithSigner(signeePubKey *PublicKey, signerPubKey *P
return sig.Sign(s, nil, config)
}
// CrossSignKey creates PrimaryKeyBinding signature in sig.EmbeddedSignature by
// signing `primary` key's hash using `priv` subkey private key. Primary public
// key is the `signee` here.
func (sig *Signature) CrossSignKey(primary *PublicKey, priv *PrivateKey, config *Config) error {
if len(sig.outSubpackets) > 0 {
return fmt.Errorf("outSubpackets already exists, looks like CrossSignKey was called after Sign")
}
sig.EmbeddedSignature = &Signature{
CreationTime: sig.CreationTime,
SigType: SigTypePrimaryKeyBinding,
PubKeyAlgo: priv.PubKeyAlgo,
Hash: sig.Hash,
}
h, err := keySignatureHash(primary, &priv.PublicKey, sig.Hash)
if err != nil {
return err
}
return sig.EmbeddedSignature.Sign(h, priv, config)
}
// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
// called first.
func (sig *Signature) Serialize(w io.Writer) (err error) {
@ -832,6 +867,14 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression})
}
if sig.EmbeddedSignature != nil {
buf := bytes.NewBuffer(nil)
if err := sig.EmbeddedSignature.Serialize(buf); err == nil {
byteContent := buf.Bytes()[2:] // skip 2-byte length header
subpackets = append(subpackets, outputSubpacket{false, embeddedSignatureSubpacket, true, byteContent})
}
}
return
}

View file

@ -91,10 +91,10 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunc
return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
}
plaintextKey = plaintextKey[1:]
if l := len(plaintextKey); l == 0 || l%cipherFunc.blockSize() != 0 {
return nil, cipherFunc, errors.StructuralError("length of decrypted key not a multiple of block size")
if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() {
return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " +
"not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")")
}
return plaintextKey, cipherFunc, nil
}

View file

@ -61,6 +61,9 @@ type MessageDetails struct {
Signature *packet.Signature // the signature packet itself, if v4 (default)
SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature
// Does the Message include multiple signatures? Also called "nested signatures".
MultiSig bool
decrypted io.ReadCloser
}
@ -158,8 +161,15 @@ FindKey:
continue
}
if !pk.key.PrivateKey.Encrypted {
if pk.key.PrivateKey.PrivateKey == nil {
// Key is stubbed
continue
}
if len(pk.encryptedKey.Key) == 0 {
pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
err := pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
if err != nil {
continue
}
}
if len(pk.encryptedKey.Key) == 0 {
continue
@ -244,8 +254,17 @@ FindLiteralData:
return nil, err
}
case *packet.OnePassSignature:
if !p.IsLast {
return nil, errors.UnsupportedError("nested signatures")
if md.IsSigned {
// If IsSigned is set, it means we have multiple
// OnePassSignature packets.
md.MultiSig = true
if md.SignedBy != nil {
// We've already found the signature we were looking
// for, made by key that we had in keyring and can
// check signature against. Continue with that instead
// of trying to find another.
continue FindLiteralData
}
}
h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
@ -329,29 +348,54 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
n, err = scr.md.LiteralData.Body.Read(buf)
scr.wrappedHash.Write(buf[:n])
if err == io.EOF {
var p packet.Packet
p, scr.md.SignatureError = scr.packets.Next()
if scr.md.SignatureError != nil {
return
}
var ok bool
if scr.md.Signature, ok = p.(*packet.Signature); ok {
var err error
if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil {
if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) {
err = errors.StructuralError("bad key fingerprint")
for {
var p packet.Packet
p, scr.md.SignatureError = scr.packets.Next()
if scr.md.SignatureError != nil {
if scr.md.MultiSig {
// If we are in MultiSig, we might have found other
// signature that cannot be verified using our key.
// Clear Signature field so it's clear for consumers
// that this message failed to verify.
scr.md.Signature = nil
}
return
}
if err == nil {
err = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
var ok bool
if scr.md.Signature, ok = p.(*packet.Signature); ok {
var err error
if keyID := scr.md.Signature.IssuerKeyId; keyID != nil {
if *keyID != scr.md.SignedBy.PublicKey.KeyId {
if scr.md.MultiSig {
continue // try again to find a sig we can verify
}
err = errors.StructuralError("bad key id")
}
}
if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil {
if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) {
if scr.md.MultiSig {
continue // try again to find a sig we can verify
}
err = errors.StructuralError("bad key fingerprint")
}
}
if err == nil {
err = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
}
scr.md.SignatureError = err
} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok {
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3)
} else {
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
return
}
scr.md.SignatureError = err
} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok {
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3)
} else {
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
return
// Parse only one packet by default, unless message is MultiSig. Then
// we ask for more packets after discovering non-matching signature,
// until we find one that we can verify.
break
}
// The SymmetricallyEncrypted packet, if any, might have an

View file

@ -458,7 +458,18 @@ func AttachedSign(out io.WriteCloser, signed Entity, hints *FileHints,
return
}
hasher := crypto.SHA512
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 := config.Hash() // defaults to SHA-256
ops := &packet.OnePassSignature{
SigType: packet.SigTypeBinary,