func TestParse(t *testing.T) { b, rest := Decode(clearsignInput) if b == nil { t.Fatal("failed to decode clearsign message") } if !bytes.Equal(rest, []byte("trailing")) { t.Errorf("unexpected remaining bytes returned: %s", string(rest)) } if b.ArmoredSignature.Type != "PGP SIGNATURE" { t.Errorf("bad armor type, got:%s, want:PGP SIGNATURE", b.ArmoredSignature.Type) } expected := []byte("Hello world\r\nline 2") if !bytes.Equal(b.Bytes, expected) { t.Errorf("bad body, got:%x want:%x", b.Bytes, expected) } expected = []byte("Hello world\nline 2\n") if !bytes.Equal(b.Plaintext, expected) { t.Errorf("bad plaintext, got:%x want:%x", b.Plaintext, expected) } keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(signingKey)) if err != nil { t.Errorf("failed to parse public key: %s", err) } if _, err := openpgp.CheckDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body); err != nil { t.Errorf("failed to check signature: %s", err) } }
// Verify() checks the validity of a signature for some data, // and returns a boolean set to true if valid and an OpenPGP Entity func Verify(data string, signature string, keyring io.Reader) (valid bool, entity *openpgp.Entity, err error) { valid = false // re-armor signature and transform into io.Reader sigReader := strings.NewReader(reArmor(signature)) // decode armor sigBlock, err := armor.Decode(sigReader) if err != nil { panic(err) } if sigBlock.Type != "PGP SIGNATURE" { err = fmt.Errorf("Wrong signature type '%s'", sigBlock.Type) panic(err) } // convert to io.Reader srcReader := strings.NewReader(data) // open the keyring ring, err := openpgp.ReadKeyRing(keyring) if err != nil { panic(err) } entity, err = openpgp.CheckDetachedSignature(ring, srcReader, sigBlock.Body) if err != nil { panic(err) } // we passed, signature is valid valid = true return }
func main() { sigReader := strings.NewReader(sig) sigBlock, err := armor.Decode(sigReader) if err != nil { panic(err) } if sigBlock.Type != openpgp.SignatureType { panic("not a signature type") } dataReader := strings.NewReader(data) krfd, err := os.Open("/home/ulfr/.gnupg/pubring.gpg") if err != nil { panic(err) } defer krfd.Close() keyring, err := openpgp.ReadKeyRing(krfd) if err != nil { panic(err) } entity, err := openpgp.CheckDetachedSignature( keyring, dataReader, sigBlock.Body) if err != nil { panic(err) } fmt.Printf("valid signature from key %s\n", hex.EncodeToString(entity.PrimaryKey.Fingerprint[:])) }
func checkGPG(file File) (state SigState, err error) { var signer *openpgp.Entity keypath := path.Join(os.Getenv("HOME"), "/.gnupg/pubring.gpg") keys, err := os.Open(keypath) if err != nil { fmt.Printf("Could not open public keyring at %s\n", keypath) os.Exit(2) } keyring, err := openpgp.ReadKeyRing(keys) if err != nil { fmt.Printf("Error reading public keyring: %s\n", err) os.Exit(2) } if *flagBin { signer, err = openpgp.CheckDetachedSignature(keyring, bytes.NewReader(file.content), bytes.NewReader(file.signature)) } else { signer, err = openpgp.CheckArmoredDetachedSignature(keyring, bytes.NewReader(file.content), bytes.NewReader(file.signature)) } if err != nil { fmt.Printf("Invalid signature or public key not present: %s\n", err) os.Exit(2) } state.sig = signer.PrimaryKey.KeyIdString() l := len(*flagKeyid) if l > 0 { var rid string // Force the local id to be all uppercase lid := strings.ToUpper(*flagKeyid) // check the number of chars on the remote id to see if it's a // short or long id. If it's not 8 or 16, it's not valid. switch l { case 8: rid = signer.PrimaryKey.KeyIdShortString() case 16: rid = signer.PrimaryKey.KeyIdString() } if len(rid) == 0 { fmt.Printf("You did not specify a valid GPG keyid length. Must be 8 or 16 characters.") os.Exit(2) } if lid != rid { fmt.Printf("The remote file was not signed by the expected GPG Public key. Expected %s and got %s\n", lid, rid) os.Exit(2) } } state.success = true return state, nil }
func TestSigning(t *testing.T) { keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(signingKey)) if err != nil { t.Errorf("failed to parse public key: %s", err) } for i, test := range signingTests { var buf bytes.Buffer plaintext, err := Encode(&buf, keyring[0].PrivateKey, nil) if err != nil { t.Errorf("#%d: error from Encode: %s", i, err) continue } if _, err := plaintext.Write([]byte(test.in)); err != nil { t.Errorf("#%d: error from Write: %s", i, err) continue } if err := plaintext.Close(); err != nil { t.Fatalf("#%d: error from Close: %s", i, err) continue } b, _ := Decode(buf.Bytes()) if b == nil { t.Errorf("#%d: failed to decode clearsign message", i) continue } if !bytes.Equal(b.Bytes, []byte(test.signed)) { t.Errorf("#%d: bad result, got:%x, want:%x", i, b.Bytes, test.signed) continue } if !bytes.Equal(b.Plaintext, []byte(test.plaintext)) { t.Errorf("#%d: bad result, got:%x, want:%x", i, b.Plaintext, test.plaintext) continue } if _, err := openpgp.CheckDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body); err != nil { t.Errorf("#%d: failed to check signature: %s", i, err) } } }
// DecodeCheckSignature parses the inline signed PGP text, checks the signature, // and returns plain text if the signature matches. func DecodeCheckSignature(r io.Reader, armoredPublicKey string) ([]byte, error) { data, err := ioutil.ReadAll(r) if err != nil { return nil, err } b, _ := clearsign.Decode(data) if b == nil { return nil, &NotPGPSignedError{} } keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(armoredPublicKey)) if err != nil { return nil, fmt.Errorf("failed to parse public key: %v", err) } _, err = openpgp.CheckDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body) if err != nil { return nil, err } return b.Plaintext, nil }
func checkSignature(keysrc KeySource, msg []byte, sigBlock *armor.Block) *VerifyStatus { if sigBlock.Type != openpgp.SignatureType { return createVerifyFailure("armored signature type is incorrect: " + sigBlock.Type) } msgReader := bytes.NewReader(msg) bb := new(bytes.Buffer) bb.ReadFrom(sigBlock.Body) sigBytes := bb.Bytes() signer, err := openpgp.CheckDetachedSignature( keysrc.GetPublicKeyRing(), msgReader, bytes.NewReader(sigBytes)) keyId, e := getIssuerFromSignature(bytes.NewReader(sigBytes)) if e != nil { logger.Warning("could not extract issuer id from signature: " + e.Error()) } return processCheckSignatureResult(signer, keyId, err) }
func checkGPG(file *File) (state SigState, err error) { var signer *openpgp.Entity var cs *clearsign.Block keypath := path.Join(os.Getenv("HOME"), "/.gnupg/pubring.gpg") keys, err := os.Open(keypath) if err != nil { fmt.Printf("Could not open public keyring at %s\n", keypath) os.Exit(2) } keyring, err := openpgp.ReadKeyRing(keys) if err != nil { fmt.Printf("Error reading public keyring: %s\n", err) os.Exit(2) } if *flagClear { cs, _ = clearsign.Decode(file.content) if cs == nil { fmt.Printf("Problem decoding clearsign signature from file %s\n", file.name) os.Exit(2) } lsig, err := ioutil.ReadAll(cs.ArmoredSignature.Body) if err != nil { fmt.Printf("Problem reading signature from %s. Are you sure this file is clearsigned?: %s\n", file.name, err) os.Exit(2) } if len(lsig) > 0 { file.signature = lsig file.content = cs.Bytes *flagBin = true } } if *flagBin { signer, err = openpgp.CheckDetachedSignature(keyring, bytes.NewReader(file.content), bytes.NewReader(file.signature)) } else { signer, err = openpgp.CheckArmoredDetachedSignature(keyring, bytes.NewReader(file.content), bytes.NewReader(file.signature)) } if err != nil { fmt.Printf("Invalid signature or public key not present: %s\n", err) os.Exit(2) } state.sig = signer.PrimaryKey.KeyIdString() l := len(*flagKeyid) if l > 0 { var rid string // Force the local id to be all uppercase lid := strings.ToUpper(*flagKeyid) // check the number of chars on the remote id to see if it's a // short or long id. If it's not 8 or 16, it's not valid. switch l { case 8: rid = signer.PrimaryKey.KeyIdShortString() case 16: rid = signer.PrimaryKey.KeyIdString() } if len(rid) == 0 { fmt.Printf("You did not specify a valid GPG keyid length. Must be 8 or 16 characters.") os.Exit(2) } if lid != rid { fmt.Printf("The remote file was not signed by the expected GPG Public key. Expected %s and got %s\n", lid, rid) os.Exit(2) } } // Due to how clearsign works, the detached signature has to be // processed using the Bytes field, but the stripped content is located // in the Plaintext field. As we've verified the signature was valid // we can now fix the content if *flagClear { file.content = cs.Plaintext } state.success = true return state, nil }