github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/pgp_verify.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 engine 5 6 import ( 7 "bytes" 8 "errors" 9 "fmt" 10 "io" 11 12 "github.com/keybase/client/go/libkb" 13 "github.com/keybase/client/go/protocol/keybase1" 14 "github.com/keybase/go-crypto/openpgp" 15 "github.com/keybase/go-crypto/openpgp/armor" 16 "github.com/keybase/go-crypto/openpgp/clearsign" 17 "github.com/keybase/go-crypto/openpgp/packet" 18 ) 19 20 type PGPVerifyArg struct { 21 Source io.Reader 22 Signature []byte 23 SignedBy string 24 } 25 26 // PGPVerify is an engine. 27 type PGPVerify struct { 28 arg *PGPVerifyArg 29 source io.Reader 30 signStatus *libkb.SignatureStatus 31 signer *libkb.User 32 libkb.Contextified 33 } 34 35 // NewPGPVerify creates a PGPVerify engine. 36 func NewPGPVerify(g *libkb.GlobalContext, arg *PGPVerifyArg) *PGPVerify { 37 return &PGPVerify{ 38 arg: arg, 39 Contextified: libkb.NewContextified(g), 40 } 41 } 42 43 // Name is the unique engine name. 44 func (e *PGPVerify) Name() string { 45 return "PGPVerify" 46 } 47 48 // GetPrereqs returns the engine prereqs. 49 func (e *PGPVerify) Prereqs() Prereqs { 50 return Prereqs{} 51 } 52 53 // RequiredUIs returns the required UIs. 54 func (e *PGPVerify) RequiredUIs() []libkb.UIKind { 55 return []libkb.UIKind{libkb.PgpUIKind} 56 } 57 58 // SubConsumers returns the other UI consumers for this engine. 59 func (e *PGPVerify) SubConsumers() []libkb.UIConsumer { 60 return []libkb.UIConsumer{ 61 &PGPDecrypt{}, 62 &ScanKeys{}, 63 &ResolveThenIdentify2{}, 64 } 65 } 66 67 // Run starts the engine. 68 func (e *PGPVerify) Run(m libkb.MetaContext) error { 69 var err error 70 defer m.Trace("PGPVerify#Run", &err)() 71 var sc libkb.StreamClassification 72 sc, e.source, err = libkb.ClassifyStream(e.arg.Source) 73 74 // For a Detached signature, we'll be expecting an UnknownStreamError 75 if err != nil { 76 if _, ok := err.(libkb.UnknownStreamError); !ok || len(e.arg.Signature) == 0 { 77 return err 78 } 79 } 80 81 if sc.Format == libkb.CryptoMessageFormatPGP && sc.Type == libkb.CryptoMessageTypeClearSignature { 82 err = e.runClearsign(m) 83 return err 84 } 85 if len(e.arg.Signature) == 0 { 86 err = e.runAttached(m) 87 return err 88 } 89 err = e.runDetached(m) 90 return err 91 } 92 93 func (e *PGPVerify) SignatureStatus() *libkb.SignatureStatus { 94 return e.signStatus 95 } 96 97 func (e *PGPVerify) Signer() *libkb.User { 98 return e.signer 99 } 100 101 // runAttached verifies an attached signature 102 func (e *PGPVerify) runAttached(m libkb.MetaContext) error { 103 arg := &PGPDecryptArg{ 104 Source: e.source, 105 Sink: libkb.NopWriteCloser{W: io.Discard}, 106 AssertSigned: true, 107 SignedBy: e.arg.SignedBy, 108 } 109 eng := NewPGPDecrypt(m.G(), arg) 110 if err := RunEngine2(m, eng); err != nil { 111 return err 112 } 113 e.signStatus = eng.SignatureStatus() 114 e.signer = eng.Signer() 115 116 return nil 117 } 118 119 // runDetached verifies a detached signature 120 func (e *PGPVerify) runDetached(m libkb.MetaContext) error { 121 sk, err := NewScanKeys(m) 122 if err != nil { 123 return err 124 } 125 checkfn := openpgp.CheckDetachedSignature 126 if libkb.IsArmored(e.arg.Signature) { 127 checkfn = openpgp.CheckArmoredDetachedSignature 128 } 129 signer, err := checkfn(sk, e.source, bytes.NewReader(e.arg.Signature)) 130 if err != nil { 131 return err 132 } 133 hashMethod, _, err := libkb.ExtractPGPSignatureHashMethod(sk, e.arg.Signature) 134 if err != nil { 135 return err 136 } 137 138 e.signer = sk.KeyOwnerByEntity(signer) 139 e.signStatus = &libkb.SignatureStatus{IsSigned: true} 140 141 if !libkb.IsHashSecure(hashMethod) { 142 e.signStatus.Warnings = append( 143 e.signStatus.Warnings, 144 libkb.NewHashSecurityWarning( 145 libkb.HashSecurityWarningSignatureHash, 146 hashMethod, 147 nil, 148 ), 149 ) 150 } 151 152 if signer != nil { 153 if len(signer.UnverifiedRevocations) > 0 { 154 return libkb.BadSigError{ 155 E: fmt.Sprintf("Key %x belonging to %q has been revoked by its designated revoker.", signer.PrimaryKey.KeyId, e.signer.GetName()), 156 } 157 } 158 159 e.signStatus.Verified = true 160 e.signStatus.Entity = signer 161 if err := e.checkSignedBy(m); err != nil { 162 return err 163 } 164 165 var r io.Reader = bytes.NewReader(e.arg.Signature) 166 if libkb.IsArmored(e.arg.Signature) { 167 block, err := armor.Decode(r) 168 if err != nil { 169 return err 170 } 171 r = block.Body 172 } 173 174 p, err := packet.Read(r) 175 if err != nil { 176 return err 177 } 178 179 if val, ok := p.(*packet.Signature); ok { 180 e.signStatus.SignatureTime = val.CreationTime 181 } else if val, ok := p.(*packet.SignatureV3); ok { 182 e.signStatus.SignatureTime = val.CreationTime 183 } 184 185 if warnings := libkb.NewPGPKeyBundle(signer).SecurityWarnings( 186 libkb.HashSecurityWarningSignersIdentityHash, 187 ); len(warnings) > 0 { 188 e.signStatus.Warnings = append( 189 e.signStatus.Warnings, 190 warnings..., 191 ) 192 } 193 194 fingerprint := libkb.PGPFingerprint(signer.PrimaryKey.Fingerprint) 195 err = OutputSignatureSuccess(m, fingerprint, e.signer, e.signStatus.SignatureTime, e.signStatus.Warnings) 196 if err != nil { 197 return err 198 } 199 } 200 201 return nil 202 } 203 204 // runClearsign verifies a clearsign signature 205 func (e *PGPVerify) runClearsign(m libkb.MetaContext) error { 206 // clearsign decode only works with the whole data slice, not a reader 207 // so have to read it all here: 208 msg, err := io.ReadAll(e.source) 209 if err != nil { 210 return err 211 } 212 b, _ := clearsign.Decode(msg) 213 if b == nil { 214 return errors.New("Unable to decode clearsigned message") 215 } 216 217 sigBody, err := io.ReadAll(b.ArmoredSignature.Body) 218 if err != nil { 219 return err 220 } 221 222 sk, err := NewScanKeys(m) 223 if err != nil { 224 return err 225 } 226 227 signer, err := openpgp.CheckDetachedSignature(sk, bytes.NewReader(b.Bytes), bytes.NewReader(sigBody)) 228 if err != nil { 229 return fmt.Errorf("Check sig error: %s", err) 230 } 231 hashMethod, _, err := libkb.ExtractPGPSignatureHashMethod(sk, sigBody) 232 if err != nil { 233 return err 234 } 235 236 e.signer = sk.KeyOwnerByEntity(signer) 237 e.signStatus = &libkb.SignatureStatus{IsSigned: true} 238 239 if !libkb.IsHashSecure(hashMethod) { 240 e.signStatus.Warnings = append( 241 e.signStatus.Warnings, 242 libkb.NewHashSecurityWarning( 243 libkb.HashSecurityWarningSignatureHash, 244 hashMethod, 245 nil, 246 ), 247 ) 248 } 249 250 if signer != nil { 251 if len(signer.UnverifiedRevocations) > 0 { 252 return libkb.BadSigError{ 253 E: fmt.Sprintf("Key %x belonging to %q has been revoked by its designated revoker.", signer.PrimaryKey.KeyId, e.signer.GetName()), 254 } 255 } 256 257 e.signStatus.Verified = true 258 e.signStatus.Entity = signer 259 if err := e.checkSignedBy(m); err != nil { 260 return err 261 } 262 263 p, err := packet.Read(bytes.NewReader(sigBody)) 264 if err != nil { 265 return err 266 } 267 268 if val, ok := p.(*packet.Signature); ok { 269 e.signStatus.SignatureTime = val.CreationTime 270 } else if val, ok := p.(*packet.SignatureV3); ok { 271 e.signStatus.SignatureTime = val.CreationTime 272 } 273 274 if warnings := libkb.NewPGPKeyBundle(signer).SecurityWarnings( 275 libkb.HashSecurityWarningSignersIdentityHash, 276 ); len(warnings) > 0 { 277 e.signStatus.Warnings = append( 278 e.signStatus.Warnings, 279 warnings..., 280 ) 281 } 282 283 fingerprint := libkb.PGPFingerprint(signer.PrimaryKey.Fingerprint) 284 err = OutputSignatureSuccess(m, fingerprint, e.signer, e.signStatus.SignatureTime, e.signStatus.Warnings) 285 if err != nil { 286 return err 287 } 288 } 289 290 return nil 291 } 292 293 func (e *PGPVerify) checkSignedBy(m libkb.MetaContext) error { 294 if len(e.arg.SignedBy) == 0 { 295 // no assertion necessary 296 return nil 297 } 298 if !e.signStatus.Verified || e.signStatus.Entity == nil || e.signer == nil { 299 // signature not valid, so no need to assert 300 return nil 301 } 302 303 // have: a valid signature, the signature's owner, and a user assertion to 304 // match against 305 m.Debug("checking signed by assertion: %q", e.arg.SignedBy) 306 307 // load the user in SignedBy 308 arg := keybase1.Identify2Arg{ 309 UserAssertion: e.arg.SignedBy, 310 AlwaysBlock: true, 311 NeedProofSet: true, 312 NoSkipSelf: true, 313 } 314 eng := NewResolveThenIdentify2(e.G(), &arg) 315 if err := RunEngine2(m, eng); err != nil { 316 return err 317 } 318 res, err := eng.Result(m) 319 if err != nil { 320 return err 321 } 322 signByUser := res.Upk 323 324 // check if it is equal to signature owner 325 if !e.signer.GetUID().Equal(signByUser.GetUID()) { 326 return libkb.BadSigError{ 327 E: fmt.Sprintf("Signer %q did not match signed by assertion %q", e.signer.GetName(), e.arg.SignedBy), 328 } 329 } 330 return nil 331 }