func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) os.Error { var subKey Subkey subKey.PublicKey = pub subKey.PrivateKey = priv p, err := packets.Next() if err == os.EOF { return io.ErrUnexpectedEOF } if err != nil { return error.StructuralError("subkey signature invalid: " + err.String()) } var ok bool subKey.Sig, ok = p.(*packet.Signature) if !ok { return error.StructuralError("subkey packet not followed by signature") } if subKey.Sig.SigType != packet.SigTypeSubkeyBinding { return error.StructuralError("subkey signature with wrong type") } err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig) if err != nil { return error.StructuralError("subkey signature invalid: " + err.String()) } e.Subkeys = append(e.Subkeys, subKey) return nil }
func (scr *signatureCheckReader) Read(buf []byte) (n int, err os.Error) { n, err = scr.md.LiteralData.Body.Read(buf) scr.wrappedHash.Write(buf[:n]) if err == os.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 = error.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) os.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 error.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 error.StructuralError("length of decrypted key not a multiple of block size") } } ske.Encrypted = false return nil }
// Decrypt decrypts an encrypted session key with the given private key. The // private key must have been decrypted first. func (e *EncryptedKey) Decrypt(priv *PrivateKey) 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(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1) case PubKeyAlgoElGamal: c1 := new(big.Int).SetBytes(e.encryptedMPI1) c2 := new(big.Int).SetBytes(e.encryptedMPI2) b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) default: err = error_.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 error_.StructuralError("EncryptedKey checksum incorrect") } return nil }
func readHeader(r io.Reader) (tag uint8, length uint64, err os.Error) { var buf [4]byte _, err = io.ReadFull(r, buf[0:1]) if err != nil { return } if buf[0]&0x80 == 0 { err = error.StructuralError("tag byte does not have MSB set") return } if buf[0]&0x40 == 0 { // Old format packet tag = (buf[0] & 0x3f) >> 2 lengthType := buf[0] & 3 if lengthType == 3 { err = error.Unsupported("indeterminate length packet") return } lengthBytes := 1 << lengthType _, err = io.ReadFull(r, buf[0:lengthBytes]) if err != nil { return } for i := 0; i < lengthBytes; i++ { length <<= 8 length |= uint64(buf[i]) } return } // New format packet tag = buf[0] & 0x3f _, err = io.ReadFull(r, buf[0:1]) if err != nil { return } switch { case buf[0] < 192: length = uint64(buf[0]) case buf[0] < 224: length = uint64(buf[0]-192) << 8 _, err = io.ReadFull(r, buf[0:1]) if err != nil { return } length += uint64(buf[0]) + 192 case buf[0] < 255: err = error.Unsupported("chunked packet") default: _, err := io.ReadFull(r, buf[0:4]) if err != nil { return } length = uint64(buf[0])<<24 | uint64(buf[1])<<16 | uint64(buf[2])<<8 | uint64(buf[3]) } return }
// CheckDetachedSignature takes a signed file and a detached signature and // returns the signer if the signature is valid. If the signer isn't know, // UnknownIssuerError is returned. func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err os.Error) { p, err := packet.Read(signature) if err != nil { return } sig, ok := p.(*packet.Signature) if !ok { return nil, error.StructuralError("non signature packet found") } if sig.IssuerKeyId == nil { return nil, error.StructuralError("signature doesn't have an issuer") } keys := keyring.KeysById(*sig.IssuerKeyId) if len(keys) == 0 { return nil, error.UnknownIssuerError } h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) if err != nil { return } _, err = io.Copy(wrappedHash, signed) if err != nil && err != os.EOF { return } for _, key := range keys { if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign { continue } err = key.PublicKey.VerifySignature(h, sig) if err == nil { return key.Entity, nil } } if err != nil { return } return nil, error.UnknownIssuerError }
// Decrypt decrypts an encrypted private key using a passphrase. func (pk *PrivateKey) Decrypt(passphrase []byte) os.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 := pk.encryptedData cfb.XORKeyStream(data, data) if pk.sha1Checksum { if len(data) < sha1.Size { return error.StructuralError("truncated private key data") } h := sha1.New() h.Write(data[:len(data)-sha1.Size]) sum := h.Sum() if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { return error.StructuralError("private key checksum failure") } data = data[:len(data)-sha1.Size] } else { if len(data) < 2 { return error.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 error.StructuralError("private key checksum failure") } data = data[:len(data)-2] } return pk.parsePrivateKey(data) }
// 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 os.Error) { for len(subpackets) > 0 { subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) if err != nil { return } } if sig.CreationTime == 0 { err = error.StructuralError("no creation time in signature") } return }
// 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 os.Error) { var buf [4]byte _, err = io.ReadFull(r, buf[:1]) if err != nil { return } if buf[0]&0x80 == 0 { err = error.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 }
// DecryptRSA decrypts an RSA encrypted session key with the given private key. func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) { if e.Algo != PubKeyAlgoRSA && e.Algo != PubKeyAlgoRSAEncryptOnly { return error.InvalidArgumentError("EncryptedKey not RSA encrypted") } b, err := rsa.DecryptPKCS1v15(rand.Reader, priv, e.Encrypted) if err != nil { return } e.CipherFunc = CipherFunction(b[0]) e.Key = b[1 : len(b)-2] expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) var checksum uint16 for _, v := range e.Key { checksum += uint16(v) } if checksum != expectedChecksum { return error.StructuralError("EncryptedKey checksum incorrect") } return }
// readEntity reads an entity (public key, identities, subkeys etc) from the // given Reader. func readEntity(packets *packet.Reader) (*Entity, os.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, error.StructuralError("first packet was not a public/private key") } else { e.PrimaryKey = &e.PrivateKey.PublicKey } } var current *Identity EachPacket: for { p, err := packets.Next() if err == os.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 == os.EOF { return nil, io.ErrUnexpectedEOF } else if err != nil { return nil, err } sig, ok := p.(*packet.Signature) if !ok { return nil, error.StructuralError("user ID packet not followed by self-signature") } if sig.SigType == packet.SigTypePositiveCert && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, sig); err != nil { return nil, error.StructuralError("user ID self-signature invalid: " + err.String()) } current.SelfSignature = sig break } current.Signatures = append(current.Signatures, sig) } case *packet.Signature: if current == nil { return nil, error.StructuralError("signature packet found before user id packet") } 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, error.StructuralError("entity without any identities") } return e, nil }
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.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 = error.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 = error.StructuralError("signature creation time in non-hashed area") return } if len(subpacket) != 4 { err = error.StructuralError("signature creation time not four bytes") return } sig.CreationTime = binary.BigEndian.Uint32(subpacket) case signatureExpirationSubpacket: // Signature expiration time, section 5.2.3.10 if !isHashed { return } if len(subpacket) != 4 { err = error.StructuralError("expiration subpacket with bad length") return } sig.SigLifetimeSecs = new(uint32) *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) case keyExpirySubpacket: // Key expiration time, section 5.2.3.6 if !isHashed { return } if len(subpacket) != 4 { err = error.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 = error.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 = error.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 = error.StructuralError("empty key flags subpacket") return } sig.FlagsValid = true if subpacket[0]&1 != 0 { sig.FlagCertify = true } if subpacket[0]&2 != 0 { sig.FlagSign = true } if subpacket[0]&4 != 0 { sig.FlagEncryptCommunications = true } if subpacket[0]&8 != 0 { sig.FlagEncryptStorage = true } default: if isCritical { err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) return } } return Truncated: err = error.StructuralError("signature subpacket truncated") return }
// 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. func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction) (md *MessageDetails, err os.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) if p.Algo != packet.PubKeyAlgoRSA && p.Algo != packet.PubKeyAlgoRSAEncryptOnly { 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, error.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 availible 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.DecryptRSA(pk.key.PrivateKey.PrivateKey.(*rsa.PrivateKey)) } if len(pk.encryptedKey.Key) == 0 { continue } decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) if err != nil && err != error.KeyIncorrectError { 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, error.KeyIncorrectError } if prompt == nil { return nil, error.KeyIncorrectError } 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 != error.KeyIncorrectError { return nil, err } if decrypted != nil { break FindKey } } } } } md.decrypted = decrypted packets.Push(decrypted) return readSignedMessage(packets, md, keyring) }
// 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 os.Error = error.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 } }
func parseSignatureSubpacket(sig *SignaturePacket, subpacket []byte, isHashed bool) (rest []byte, err os.Error) { // RFC 4880, section 5.2.3.1 var length uint32 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 = error.StructuralError("zero length signature subpacket") return } packetType := subpacket[0] & 0x7f isCritial := subpacket[0]&0x80 == 0x80 subpacket = subpacket[1:] switch packetType { case 2: if !isHashed { err = error.StructuralError("signature creation time in non-hashed area") return } if len(subpacket) != 4 { err = error.StructuralError("signature creation time not four bytes") return } sig.CreationTime = uint32(subpacket[0])<<24 | uint32(subpacket[1])<<16 | uint32(subpacket[2])<<8 | uint32(subpacket[3]) default: if isCritial { err = error.Unsupported("unknown critical signature subpacket") return } } return Truncated: err = error.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 = error_.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 } }