1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4package libkb 5 6import ( 7 "bytes" 8 "encoding/hex" 9 "fmt" 10 "io/ioutil" 11 "strings" 12 13 "github.com/keybase/client/go/kbcrypto" 14 keybase1 "github.com/keybase/client/go/protocol/keybase1" 15 "github.com/keybase/go-crypto/openpgp" 16 "github.com/keybase/go-crypto/openpgp/armor" 17 jsonw "github.com/keybase/go-jsonw" 18) 19 20func GetSigID(w *jsonw.Wrapper) (keybase1.SigID, error) { 21 s, err := w.GetString() 22 if err != nil { 23 return "", err 24 } 25 return keybase1.SigIDFromString(s) 26} 27 28func GetSigIDBase(w *jsonw.Wrapper) (keybase1.SigIDBase, error) { 29 s, err := w.GetString() 30 if err != nil { 31 return "", err 32 } 33 return keybase1.SigIDBaseFromString(s) 34} 35 36type ParsedSig struct { 37 Block *armor.Block 38 SigBody []byte 39 MD *openpgp.MessageDetails 40 LiteralData []byte 41} 42 43func PGPOpenSig(armored string) (ps *ParsedSig, err error) { 44 pso := ParsedSig{} 45 pso.Block, err = armor.Decode(strings.NewReader(cleanPGPInput(armored))) 46 if err != nil { 47 return 48 } 49 pso.SigBody, err = ioutil.ReadAll(pso.Block.Body) 50 if err != nil { 51 return 52 } 53 ps = &pso 54 return 55} 56 57// OpenSig takes an armored PGP or Keybase signature and opens 58// the armor. It will return the body of the signature, the 59// sigID of the body, or an error if it didn't work out. 60func OpenSig(armored string) (ret []byte, id keybase1.SigIDBase, err error) { 61 if isPGPBundle(armored) { 62 var ps *ParsedSig 63 if ps, err = PGPOpenSig(armored); err == nil { 64 ret = ps.SigBody 65 id = ps.ID() 66 } 67 } else { 68 if ret, err = KbOpenSig(armored); err == nil { 69 id = kbcrypto.ComputeSigIDFromSigBody(ret) 70 } 71 } 72 return 73} 74 75// SigExtractPayloadAndKID extracts the payload and KID of the key that 76// was supposedly used to sign this message. A KID will only be returned 77// for KB messages, and not for PGP messages 78func SigExtractPayloadAndKID(armored string) (payload []byte, kid keybase1.KID, sigID keybase1.SigIDBase, err error) { 79 if isPGPBundle(armored) { 80 payload, sigID, err = SigExtractPGPPayload(armored) 81 } else { 82 payload, kid, sigID, err = SigExtractKbPayloadAndKID(armored) 83 } 84 return payload, kid, sigID, err 85} 86 87func SigAssertPayload(armored string, expected []byte) (sigID keybase1.SigIDBase, err error) { 88 if isPGPBundle(armored) { 89 return SigAssertPGPPayload(armored, expected) 90 } 91 return SigAssertKbPayload(armored, expected) 92} 93 94func SigAssertPGPPayload(armored string, expected []byte) (sigID keybase1.SigIDBase, err error) { 95 var ps *ParsedSig 96 ps, err = PGPOpenSig(armored) 97 if err != nil { 98 return 99 } 100 if err = ps.AssertPayload(expected); err != nil { 101 ps = nil 102 return 103 } 104 sigID = ps.ID() 105 return 106} 107 108func SigExtractPGPPayload(armored string) (payload []byte, sigID keybase1.SigIDBase, err error) { 109 var ps *ParsedSig 110 ps, err = PGPOpenSig(armored) 111 if err != nil { 112 return nil, sigID, err 113 } 114 payload, err = ps.ExtractPayload() 115 if err != nil { 116 return nil, sigID, err 117 } 118 return payload, ps.ID(), nil 119} 120 121func (ps *ParsedSig) ExtractPayload() (payload []byte, err error) { 122 123 ring := EmptyKeyRing{} 124 md, err := openpgp.ReadMessage(bytes.NewReader(ps.SigBody), ring, nil, nil) 125 if err != nil { 126 return nil, err 127 } 128 data, err := ioutil.ReadAll(md.UnverifiedBody) 129 if err != nil { 130 return nil, err 131 } 132 return data, nil 133} 134 135func (ps *ParsedSig) AssertPayload(expected []byte) error { 136 137 data, err := ps.ExtractPayload() 138 if err != nil { 139 return err 140 } 141 142 if !FastByteArrayEq(data, expected) { 143 err = fmt.Errorf("Signature did not contain expected text") 144 return err 145 } 146 return nil 147} 148 149func (ps *ParsedSig) Verify(k PGPKeyBundle) (err error) { 150 ps.MD, err = openpgp.ReadMessage(bytes.NewReader(ps.SigBody), k, nil, nil) 151 if err != nil { 152 return 153 } 154 if !ps.MD.IsSigned || ps.MD.SignedBy == nil { 155 err = fmt.Errorf("Message wasn't signed") 156 return 157 } 158 if !k.MatchesKey(ps.MD.SignedBy) { 159 err = fmt.Errorf("Got wrong SignedBy key %v", 160 hex.EncodeToString(ps.MD.SignedBy.PublicKey.Fingerprint[:])) 161 return 162 } 163 if ps.MD.UnverifiedBody == nil { 164 err = fmt.Errorf("no signed material found") 165 return 166 } 167 168 ps.LiteralData, err = ioutil.ReadAll(ps.MD.UnverifiedBody) 169 if err != nil { 170 return 171 } 172 173 // We'll see a sig error here after reading in the UnverifiedBody above, 174 // if there was one to see. 175 if err = ps.MD.SignatureError; err != nil { 176 return 177 } 178 179 if ps.MD.Signature == nil && ps.MD.SignatureV3 == nil { 180 err = fmt.Errorf("No available signature after checking signature") 181 return 182 } 183 184 // Hopefully by here we've covered all of our bases. 185 return nil 186} 187 188func (ps *ParsedSig) ID() keybase1.SigIDBase { 189 return kbcrypto.ComputeSigIDFromSigBody(ps.SigBody) 190} 191 192func IsPGPSig(s string) bool { 193 return strings.HasPrefix(s, "-----BEGIN PGP MESSAGE-----") 194} 195