func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { var subKey Subkey subKey.PublicKey = pub subKey.PrivateKey = priv p, err := packets.Next() if err == io.EOF { return io.ErrUnexpectedEOF } if err != nil { return errors.StructuralError("subkey signature invalid: " + err.Error()) } var ok bool subKey.Sig, ok = p.(*packet.Signature) if !ok { return errors.StructuralError("subkey packet not followed by signature") } if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation { return errors.StructuralError("subkey signature with wrong type") } err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig) if err != nil { return errors.StructuralError("subkey signature invalid: " + err.Error()) } e.Subkeys = append(e.Subkeys, subKey) return nil }
// 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 { // 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 }
// CheckDetachedSignature takes a signed file and a detached signature and // returns the signer if the signature is valid. If the signer isn't known, // ErrUnknownIssuer is returned. func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { p, err := packet.Read(signature) if err != nil { return } var issuerKeyId uint64 var hashFunc crypto.Hash var sigType packet.SignatureType switch sig := p.(type) { case *packet.Signature: if sig.IssuerKeyId == nil { return nil, errors.StructuralError("signature doesn't have an issuer") } issuerKeyId = *sig.IssuerKeyId hashFunc = sig.Hash sigType = sig.SigType case *packet.SignatureV3: issuerKeyId = sig.IssuerKeyId hashFunc = sig.Hash sigType = sig.SigType default: return nil, errors.StructuralError("non signature packet found") } h, wrappedHash, err := hashForSignature(hashFunc, sigType) if err != nil { return } _, err = io.Copy(wrappedHash, signed) if err != nil && err != io.EOF { return } keys := keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) if len(keys) == 0 { return nil, errors.ErrUnknownIssuer } for _, key := range keys { switch sig := p.(type) { case *packet.Signature: err = key.PublicKey.VerifySignature(h, sig) case *packet.SignatureV3: err = key.PublicKey.VerifySignatureV3(h, sig) } if err == nil { return key.Entity, nil } } if err == nil { err = errors.ErrUnknownIssuer } return nil, err }
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 { scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") return } scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) // The SymmetricallyEncrypted packet, if any, might have an // unsigned hash of its own. In order to check this we need to // close that Reader. if scr.md.decrypted != nil { mdcErr := scr.md.decrypted.Close() if mdcErr != nil { err = mdcErr } } } return }
// Decrypt attempts to decrypt an encrypted session key. If it returns nil, // ske.Key will contain the session key. func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) error { if !ske.Encrypted { return nil } key := make([]byte, ske.CipherFunc.KeySize()) ske.s2k(key, passphrase) if len(ske.encryptedKey) == 0 { ske.Key = key } else { // the IV is all zeros iv := make([]byte, ske.CipherFunc.blockSize()) c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) c.XORKeyStream(ske.encryptedKey, ske.encryptedKey) ske.CipherFunc = CipherFunction(ske.encryptedKey[0]) if ske.CipherFunc.blockSize() == 0 { return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc))) } ske.CipherFunc = CipherFunction(ske.encryptedKey[0]) ske.Key = ske.encryptedKey[1:] if len(ske.Key)%ske.CipherFunc.blockSize() != 0 { ske.Key = nil return errors.StructuralError("length of decrypted key not a multiple of block size") } } ske.Encrypted = false return nil }
// parseRSA parses RSA public key material from the given Reader. See RFC 4880, // section 5.5.2. func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) { if pk.n.bytes, pk.n.bitLength, err = readMPI(r); err != nil { return } if pk.e.bytes, pk.e.bitLength, err = readMPI(r); err != nil { return } // RFC 4880 Section 12.2 requires the low 8 bytes of the // modulus to form the key id. if len(pk.n.bytes) < 8 { return errors.StructuralError("v3 public key modulus is too short") } if len(pk.e.bytes) > 3 { err = errors.UnsupportedError("large public exponent") return } rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} for i := 0; i < len(pk.e.bytes); i++ { rsa.E <<= 8 rsa.E |= int(pk.e.bytes[i]) } pk.PublicKey = rsa return }
// Decrypt decrypts an encrypted session key with the given private key. The // 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 { var err error var b []byte // TODO(agl): use session key decryption routines here to avoid // padding oracle attacks. switch priv.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes) case PubKeyAlgoElGamal: c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) default: err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) } if err != nil { return err } e.CipherFunc = CipherFunction(b[0]) e.Key = b[1 : len(b)-2] expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) checksum := checksumKeyMaterial(e.Key) if checksum != expectedChecksum { return errors.StructuralError("EncryptedKey checksum incorrect") } return nil }
// Push causes the Reader to start reading from a new io.Reader. When an EOF // error is seen from the new io.Reader, it is popped and the Reader continues // to read from the next most recent io.Reader. Push returns a StructuralError // if pushing the reader would exceed the maximum recursion level, otherwise it // returns nil. func (r *Reader) Push(reader io.Reader) (err error) { if len(r.readers) >= maxReaders { return errors.StructuralError("too many layers of packets") } r.readers = append(r.readers, reader) return nil }
// Returns the key ID used to sign a message. This method is extracted // from `openpgp.CheckDetachedSignature()`, which only reports that a // key wasn't found, not *which* key wasn't found. func signerKeyId(signature []byte) (uint64, error) { p, err := packet.Read(bytes.NewReader(signature)) if err != nil { return 0, err } switch sig := p.(type) { case *packet.Signature: if sig.IssuerKeyId == nil { return 0, errors.StructuralError("signature doesn't have an issuer") } return *sig.IssuerKeyId, nil case *packet.SignatureV3: return sig.IssuerKeyId, nil default: return 0, errors.StructuralError("non signature packet found") } }
// Decrypt decrypts an encrypted private key using a passphrase. func (pk *PrivateKey) Decrypt(passphrase []byte) error { if !pk.Encrypted { return nil } key := make([]byte, pk.cipher.KeySize()) pk.s2k(key, passphrase) block := pk.cipher.new(key) cfb := cipher.NewCFBDecrypter(block, pk.iv) data := make([]byte, len(pk.encryptedData)) cfb.XORKeyStream(data, pk.encryptedData) if pk.sha1Checksum { if len(data) < sha1.Size { return errors.StructuralError("truncated private key data") } h := sha1.New() h.Write(data[:len(data)-sha1.Size]) sum := h.Sum(nil) if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { return errors.StructuralError("private key checksum failure") } data = data[:len(data)-sha1.Size] } else { if len(data) < 2 { return errors.StructuralError("truncated private key data") } var sum uint16 for i := 0; i < len(data)-2; i++ { sum += uint16(data[i]) } if data[len(data)-2] != uint8(sum>>8) || data[len(data)-1] != uint8(sum) { return errors.StructuralError("private key checksum failure") } data = data[:len(data)-2] } return pk.parsePrivateKey(data) }
// readHeader parses a packet header and returns an io.Reader which will return // the contents of the packet. See RFC 4880, section 4.2. func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) { var buf [4]byte _, err = io.ReadFull(r, buf[:1]) if err != nil { return } if buf[0]&0x80 == 0 { err = errors.StructuralError("tag byte does not have MSB set") return } if buf[0]&0x40 == 0 { // Old format packet tag = packetType((buf[0] & 0x3f) >> 2) lengthType := buf[0] & 3 if lengthType == 3 { length = -1 contents = r return } lengthBytes := 1 << lengthType _, err = readFull(r, buf[0:lengthBytes]) if err != nil { return } for i := 0; i < lengthBytes; i++ { length <<= 8 length |= int64(buf[i]) } contents = &spanReader{r, length} return } // New format packet tag = packetType(buf[0] & 0x3f) length, isPartial, err := readLength(r) if err != nil { return } if isPartial { contents = &partialLengthReader{ remaining: length, isPartial: true, r: r, } length = -1 } else { contents = &spanReader{r, length} } return }
// parseSignatureSubpackets parses subpackets of the main signature packet. See // RFC 4880, section 5.2.3.1. func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { for len(subpackets) > 0 { subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) if err != nil { return } } if sig.CreationTime.IsZero() { err = errors.StructuralError("no creation time in signature") } return }
func readPublicSigningKey(keyf io.Reader) (*packet.PublicKey, error) { keypackets := packet.NewReader(keyf) p, err := keypackets.Next() if err != nil { return nil, err } switch pkt := p.(type) { case *packet.PublicKey: debug("key: ", pkt) return pkt, nil default: log.Printf("ReadPublicSigningKey: got %T, want *packet.PublicKey", pkt) } return nil, errors.StructuralError("expected first packet to be PublicKey") }
func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) { // RFC 4880, section 5.2.3.1 var subLen uint32 if len(contents) < 1 { goto Truncated } subPacket = &OpaqueSubpacket{} switch { case contents[0] < 192: subHeaderLen = 2 // 1 length byte, 1 subtype byte if len(contents) < subHeaderLen { goto Truncated } subLen = uint32(contents[0]) contents = contents[1:] case contents[0] < 255: subHeaderLen = 3 // 2 length bytes, 1 subtype if len(contents) < subHeaderLen { goto Truncated } subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192 contents = contents[2:] default: subHeaderLen = 6 // 5 length bytes, 1 subtype if len(contents) < subHeaderLen { goto Truncated } subLen = uint32(contents[1])<<24 | uint32(contents[2])<<16 | uint32(contents[3])<<8 | uint32(contents[4]) contents = contents[5:] } if subLen > uint32(len(contents)) || subLen == 0 { goto Truncated } subPacket.SubType = contents[0] subPacket.Contents = contents[1:subLen] return Truncated: err = errors.StructuralError("subpacket truncated") return }
// Decrypt attempts to decrypt an encrypted session key and returns the key and // the cipher to use when decrypting a subsequent Symmetrically Encrypted Data // packet. func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) { key := make([]byte, ske.CipherFunc.KeySize()) ske.s2k(key, passphrase) if len(ske.encryptedKey) == 0 { return key, ske.CipherFunc, nil } // the IV is all zeros iv := make([]byte, ske.CipherFunc.blockSize()) c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) plaintextKey := make([]byte, len(ske.encryptedKey)) c.XORKeyStream(plaintextKey, ske.encryptedKey) cipherFunc := CipherFunction(plaintextKey[0]) if cipherFunc.blockSize() == 0 { return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.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") } return plaintextKey, cipherFunc, nil }
// CheckDetachedSignature takes a signed file and a detached signature and // returns the signer if the signature is valid. If the signer isn't known, // ErrUnknownIssuer is returned. func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { var issuerKeyId uint64 var hashFunc crypto.Hash var sigType packet.SignatureType var keys []Key var p packet.Packet packets := packet.NewReader(signature) for { p, err = packets.Next() if err == io.EOF { return nil, errors.ErrUnknownIssuer } if err != nil { return nil, err } switch sig := p.(type) { case *packet.Signature: if sig.IssuerKeyId == nil { return nil, errors.StructuralError("signature doesn't have an issuer") } issuerKeyId = *sig.IssuerKeyId hashFunc = sig.Hash sigType = sig.SigType case *packet.SignatureV3: issuerKeyId = sig.IssuerKeyId hashFunc = sig.Hash sigType = sig.SigType default: return nil, errors.StructuralError("non signature packet found") } keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) if len(keys) > 0 { break } } if len(keys) == 0 { panic("unreachable") } h, wrappedHash, err := hashForSignature(hashFunc, sigType) if err != nil { return nil, err } if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { return nil, err } for _, key := range keys { switch sig := p.(type) { case *packet.Signature: err = key.PublicKey.VerifySignature(h, sig) case *packet.SignatureV3: err = key.PublicKey.VerifySignatureV3(h, sig) default: panic("unreachable") } if err == nil { return key.Entity, nil } } return nil, err }
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { // RFC 4880, section 5.2.3.1 var ( length uint32 packetType signatureSubpacketType isCritical bool ) switch { case subpacket[0] < 192: length = uint32(subpacket[0]) subpacket = subpacket[1:] case subpacket[0] < 255: if len(subpacket) < 2 { goto Truncated } length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 subpacket = subpacket[2:] default: if len(subpacket) < 5 { goto Truncated } length = uint32(subpacket[1])<<24 | uint32(subpacket[2])<<16 | uint32(subpacket[3])<<8 | uint32(subpacket[4]) subpacket = subpacket[5:] } if length > uint32(len(subpacket)) { goto Truncated } rest = subpacket[length:] subpacket = subpacket[:length] if len(subpacket) == 0 { err = errors.StructuralError("zero length signature subpacket") return } packetType = signatureSubpacketType(subpacket[0] & 0x7f) isCritical = subpacket[0]&0x80 == 0x80 subpacket = subpacket[1:] sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) switch packetType { case creationTimeSubpacket: if !isHashed { err = errors.StructuralError("signature creation time in non-hashed area") return } if len(subpacket) != 4 { err = errors.StructuralError("signature creation time not four bytes") return } t := binary.BigEndian.Uint32(subpacket) sig.CreationTime = time.Unix(int64(t), 0) case signatureExpirationSubpacket: // Signature expiration time, section 5.2.3.10 if !isHashed { return } if len(subpacket) != 4 { err = errors.StructuralError("expiration subpacket with bad length") return } sig.SigLifetimeSecs = new(uint32) *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) case keyExpirationSubpacket: // Key expiration time, section 5.2.3.6 if !isHashed { return } if len(subpacket) != 4 { err = errors.StructuralError("key expiration subpacket with bad length") return } sig.KeyLifetimeSecs = new(uint32) *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) case prefSymmetricAlgosSubpacket: // Preferred symmetric algorithms, section 5.2.3.7 if !isHashed { return } sig.PreferredSymmetric = make([]byte, len(subpacket)) copy(sig.PreferredSymmetric, subpacket) case issuerSubpacket: // Issuer, section 5.2.3.5 if len(subpacket) != 8 { err = errors.StructuralError("issuer subpacket with bad length") return } sig.IssuerKeyId = new(uint64) *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) case prefHashAlgosSubpacket: // Preferred hash algorithms, section 5.2.3.8 if !isHashed { return } sig.PreferredHash = make([]byte, len(subpacket)) copy(sig.PreferredHash, subpacket) case prefCompressionSubpacket: // Preferred compression algorithms, section 5.2.3.9 if !isHashed { return } sig.PreferredCompression = make([]byte, len(subpacket)) copy(sig.PreferredCompression, subpacket) case primaryUserIdSubpacket: // Primary User ID, section 5.2.3.19 if !isHashed { return } if len(subpacket) != 1 { err = errors.StructuralError("primary user id subpacket with bad length") return } sig.IsPrimaryId = new(bool) if subpacket[0] > 0 { *sig.IsPrimaryId = true } case keyFlagsSubpacket: // Key flags, section 5.2.3.21 if !isHashed { return } if len(subpacket) == 0 { 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 } case reasonForRevocationSubpacket: // Reason For Revocation, section 5.2.3.23 if !isHashed { return } if len(subpacket) == 0 { err = errors.StructuralError("empty revocation reason subpacket") return } sig.RevocationReason = new(uint8) *sig.RevocationReason = subpacket[0] sig.RevocationReasonText = string(subpacket[1:]) case featuresSubpacket: // Features subpacket, section 5.2.3.24 specifies a very general // mechanism for OpenPGP implementations to signal support for new // features. In practice, the subpacket is used exclusively to // indicate support for MDC-protected encryption. sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1 case embeddedSignatureSubpacket: // Only usage is in signatures that cross-certify // signing subkeys. section 5.2.3.26 describes the // format, with its usage described in section 11.1 if sig.EmbeddedSignature != nil { err = errors.StructuralError("Cannot have multiple embedded signatures") return } sig.EmbeddedSignature = new(Signature) // Embedded signatures are required to be v4 signatures see // section 12.1. However, we only parse v4 signatures in this // file anyway. if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { return nil, err } if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) } default: if isCritical { err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) return } } return Truncated: err = errors.StructuralError("signature subpacket truncated") return }
// base64-encoded Bytes // '=' base64 encoded checksum // -----END Type----- // where Headers is a possibly empty sequence of Key: Value lines. // // Since the armored data can be very large, this package presents a streaming // interface. type Block struct { Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE"). Header map[string]string // Optional headers. Body io.Reader // A Reader from which the contents can be read lReader lineReader oReader openpgpReader } var ArmorCorrupt error = errors.StructuralError("armor invalid") const crc24Init = 0xb704ce const crc24Poly = 0x1864cfb const crc24Mask = 0xffffff // crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1 func crc24(crc uint32, d []byte) uint32 { for _, b := range d { crc ^= uint32(b) << 16 for i := 0; i < 8; i++ { crc <<= 1 if crc&0x1000000 != 0 { crc ^= crc24Poly } }
// ReadMessage parses an OpenPGP message that may be signed and/or encrypted. // The given KeyRing should contain both public keys (for signature // verification) and, possibly encrypted, private keys for decrypting. // If config is nil, sensible defaults will be used. func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) { var p packet.Packet var symKeys []*packet.SymmetricKeyEncrypted var pubKeys []keyEnvelopePair var se *packet.SymmetricallyEncrypted packets := packet.NewReader(r) md = new(MessageDetails) md.IsEncrypted = true // The message, if encrypted, starts with a number of packets // containing an encrypted decryption key. The decryption key is either // encrypted to a public key, or with a passphrase. This loop // collects these packets. ParsePackets: for { p, err = packets.Next() if err != nil { return nil, err } switch p := p.(type) { case *packet.SymmetricKeyEncrypted: // This packet contains the decryption key encrypted with a passphrase. md.IsSymmetricallyEncrypted = true symKeys = append(symKeys, p) case *packet.EncryptedKey: // This packet contains the decryption key encrypted to a public key. md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) switch p.Algo { case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal: break default: continue } var keys []Key if p.KeyId == 0 { keys = keyring.DecryptionKeys() } else { keys = keyring.KeysById(p.KeyId) } for _, k := range keys { pubKeys = append(pubKeys, keyEnvelopePair{k, p}) } case *packet.SymmetricallyEncrypted: se = p break ParsePackets case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: // This message isn't encrypted. if len(symKeys) != 0 || len(pubKeys) != 0 { return nil, errors.StructuralError("key material not followed by encrypted message") } packets.Unread(p) return readSignedMessage(packets, nil, keyring) } } var candidates []Key var decrypted io.ReadCloser // Now that we have the list of encrypted keys we need to decrypt at // least one of them or, if we cannot, we need to call the prompt // function so that it can decrypt a key or give us a passphrase. FindKey: for { // See if any of the keys already have a private key available candidates = candidates[:0] candidateFingerprints := make(map[string]bool) for _, pk := range pubKeys { if pk.key.PrivateKey == nil { continue } if !pk.key.PrivateKey.Encrypted { if len(pk.encryptedKey.Key) == 0 { pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) } if len(pk.encryptedKey.Key) == 0 { continue } decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) if err != nil && err != errors.ErrKeyIncorrect { return nil, err } if decrypted != nil { md.DecryptedWith = pk.key break FindKey } } else { fpr := string(pk.key.PublicKey.Fingerprint[:]) if v := candidateFingerprints[fpr]; v { continue } candidates = append(candidates, pk.key) candidateFingerprints[fpr] = true } } if len(candidates) == 0 && len(symKeys) == 0 { return nil, errors.ErrKeyIncorrect } if prompt == nil { return nil, errors.ErrKeyIncorrect } passphrase, err := prompt(candidates, len(symKeys) != 0) if err != nil { return nil, err } // Try the symmetric passphrase first if len(symKeys) != 0 && passphrase != nil { for _, s := range symKeys { err = s.Decrypt(passphrase) if err == nil && !s.Encrypted { decrypted, err = se.Decrypt(s.CipherFunc, s.Key) if err != nil && err != errors.ErrKeyIncorrect { return nil, err } if decrypted != nil { break FindKey } } } } } md.decrypted = decrypted if err := packets.Push(decrypted); err != nil { return nil, err } return readSignedMessage(packets, md, keyring) }
// ReadEntity reads an entity (public key, identities, subkeys etc) from the // given Reader. func ReadEntity(packets *packet.Reader) (*Entity, error) { e := new(Entity) e.Identities = make(map[string]*Identity) p, err := packets.Next() if err != nil { return nil, err } var ok bool if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { packets.Unread(p) return nil, errors.StructuralError("first packet was not a public/private key") } else { e.PrimaryKey = &e.PrivateKey.PublicKey } } if !e.PrimaryKey.PubKeyAlgo.CanSign() { return nil, errors.StructuralError("primary key cannot be used for signatures") } var current *Identity var revocations []*packet.Signature EachPacket: for { p, err := packets.Next() if err == io.EOF { break } else if err != nil { return nil, err } switch pkt := p.(type) { case *packet.UserId: current = new(Identity) current.Name = pkt.Id current.UserId = pkt e.Identities[pkt.Id] = current for { p, err = packets.Next() if err == io.EOF { return nil, io.ErrUnexpectedEOF } else if err != nil { return nil, err } sig, ok := p.(*packet.Signature) if !ok { return nil, errors.StructuralError("user ID packet not followed by self-signature") } if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error()) } current.SelfSignature = sig break } current.Signatures = append(current.Signatures, sig) } case *packet.Signature: if pkt.SigType == packet.SigTypeKeyRevocation { revocations = append(revocations, pkt) } else if pkt.SigType == packet.SigTypeDirectSignature { // TODO: RFC4880 5.2.1 permits signatures // directly on keys (eg. to bind additional // revocation keys). } else if current == nil { return nil, errors.StructuralError("signature packet found before user id packet") } else { current.Signatures = append(current.Signatures, pkt) } case *packet.PrivateKey: if pkt.IsSubkey == false { packets.Unread(p) break EachPacket } err = addSubkey(e, packets, &pkt.PublicKey, pkt) if err != nil { return nil, err } case *packet.PublicKey: if pkt.IsSubkey == false { packets.Unread(p) break EachPacket } err = addSubkey(e, packets, pkt, nil) if err != nil { return nil, err } default: // we ignore unknown packets } } if len(e.Identities) == 0 { return nil, errors.StructuralError("entity without any identities") } for _, revocation := range revocations { err = e.PrimaryKey.VerifyRevocationSignature(revocation) if err == nil { e.Revocations = append(e.Revocations, revocation) } else { // TODO: RFC 4880 5.2.3.15 defines revocation keys. return nil, errors.StructuralError("revocation signature signed by alternate key") } } return e, nil }
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { // RFC 4880, section 5.2.3.1 var ( length uint32 packetType signatureSubpacketType isCritical bool ) switch { case subpacket[0] < 192: length = uint32(subpacket[0]) subpacket = subpacket[1:] case subpacket[0] < 255: if len(subpacket) < 2 { goto Truncated } length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 subpacket = subpacket[2:] default: if len(subpacket) < 5 { goto Truncated } length = uint32(subpacket[1])<<24 | uint32(subpacket[2])<<16 | uint32(subpacket[3])<<8 | uint32(subpacket[4]) subpacket = subpacket[5:] } if length > uint32(len(subpacket)) { goto Truncated } rest = subpacket[length:] subpacket = subpacket[:length] if len(subpacket) == 0 { err = errors.StructuralError("zero length signature subpacket") return } packetType = signatureSubpacketType(subpacket[0] & 0x7f) isCritical = subpacket[0]&0x80 == 0x80 subpacket = subpacket[1:] sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) switch packetType { case creationTimeSubpacket: if !isHashed { err = errors.StructuralError("signature creation time in non-hashed area") return } if len(subpacket) != 4 { err = errors.StructuralError("signature creation time not four bytes") return } t := binary.BigEndian.Uint32(subpacket) sig.CreationTime = time.Unix(int64(t), 0) case signatureExpirationSubpacket: // Signature expiration time, section 5.2.3.10 if !isHashed { return } if len(subpacket) != 4 { err = errors.StructuralError("expiration subpacket with bad length") return } sig.SigLifetimeSecs = new(uint32) *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) case keyExpirationSubpacket: // Key expiration time, section 5.2.3.6 if !isHashed { return } if len(subpacket) != 4 { err = errors.StructuralError("key expiration subpacket with bad length") return } sig.KeyLifetimeSecs = new(uint32) *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) case prefSymmetricAlgosSubpacket: // Preferred symmetric algorithms, section 5.2.3.7 if !isHashed { return } sig.PreferredSymmetric = make([]byte, len(subpacket)) copy(sig.PreferredSymmetric, subpacket) case issuerSubpacket: // Issuer, section 5.2.3.5 if len(subpacket) != 8 { err = errors.StructuralError("issuer subpacket with bad length") return } sig.IssuerKeyId = new(uint64) *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) case prefHashAlgosSubpacket: // Preferred hash algorithms, section 5.2.3.8 if !isHashed { return } sig.PreferredHash = make([]byte, len(subpacket)) copy(sig.PreferredHash, subpacket) case prefCompressionSubpacket: // Preferred compression algorithms, section 5.2.3.9 if !isHashed { return } sig.PreferredCompression = make([]byte, len(subpacket)) copy(sig.PreferredCompression, subpacket) case primaryUserIdSubpacket: // Primary User ID, section 5.2.3.19 if !isHashed { return } if len(subpacket) != 1 { err = errors.StructuralError("primary user id subpacket with bad length") return } sig.IsPrimaryId = new(bool) if subpacket[0] > 0 { *sig.IsPrimaryId = true } case keyFlagsSubpacket: // Key flags, section 5.2.3.21 if !isHashed { return } if len(subpacket) == 0 { 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 } case reasonForRevocationSubpacket: // Reason For Revocation, section 5.2.3.23 if !isHashed { return } if len(subpacket) == 0 { err = errors.StructuralError("empty revocation reason subpacket") return } sig.RevocationReason = new(uint8) *sig.RevocationReason = subpacket[0] sig.RevocationReasonText = string(subpacket[1:]) default: if isCritical { err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) return } } return Truncated: err = errors.StructuralError("signature subpacket truncated") return }