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