committed by
GitHub Enterprise
parent
7f14cc2751
commit
c8de2df2cf
418
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
generated
vendored
Normal file
418
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
generated
vendored
Normal file
@@ -0,0 +1,418 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package clearsign generates and processes OpenPGP, clear-signed data. See
|
||||
// RFC 4880, section 7.
|
||||
//
|
||||
// Clearsigned messages are cryptographically signed, but the contents of the
|
||||
// message are kept in plaintext so that it can be read without special tools.
|
||||
package clearsign // import "golang.org/x/crypto/openpgp/clearsign"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net/textproto"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/openpgp/armor"
|
||||
"golang.org/x/crypto/openpgp/errors"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
// A Block represents a clearsigned message. A signature on a Block can
|
||||
// be checked by passing Bytes into openpgp.CheckDetachedSignature.
|
||||
type Block struct {
|
||||
Headers textproto.MIMEHeader // Optional unverified Hash headers
|
||||
Plaintext []byte // The original message text
|
||||
Bytes []byte // The signed message
|
||||
ArmoredSignature *armor.Block // The signature block
|
||||
}
|
||||
|
||||
// start is the marker which denotes the beginning of a clearsigned message.
|
||||
var start = []byte("\n-----BEGIN PGP SIGNED MESSAGE-----")
|
||||
|
||||
// dashEscape is prefixed to any lines that begin with a hyphen so that they
|
||||
// can't be confused with endText.
|
||||
var dashEscape = []byte("- ")
|
||||
|
||||
// endText is a marker which denotes the end of the message and the start of
|
||||
// an armored signature.
|
||||
var endText = []byte("-----BEGIN PGP SIGNATURE-----")
|
||||
|
||||
// end is a marker which denotes the end of the armored signature.
|
||||
var end = []byte("\n-----END PGP SIGNATURE-----")
|
||||
|
||||
var crlf = []byte("\r\n")
|
||||
var lf = byte('\n')
|
||||
|
||||
// getLine returns the first \r\n or \n delineated line from the given byte
|
||||
// array. The line does not include the \r\n or \n. The remainder of the byte
|
||||
// array (also not including the new line bytes) is also returned and this will
|
||||
// always be smaller than the original argument.
|
||||
func getLine(data []byte) (line, rest []byte) {
|
||||
i := bytes.Index(data, []byte{'\n'})
|
||||
var j int
|
||||
if i < 0 {
|
||||
i = len(data)
|
||||
j = i
|
||||
} else {
|
||||
j = i + 1
|
||||
if i > 0 && data[i-1] == '\r' {
|
||||
i--
|
||||
}
|
||||
}
|
||||
return data[0:i], data[j:]
|
||||
}
|
||||
|
||||
// Decode finds the first clearsigned message in data and returns it, as well as
|
||||
// the suffix of data which remains after the message. Any prefix data is
|
||||
// discarded.
|
||||
//
|
||||
// If no message is found, or if the message is invalid, Decode returns nil and
|
||||
// the whole data slice. The only allowed header type is Hash, and it is not
|
||||
// verified against the signature hash.
|
||||
func Decode(data []byte) (b *Block, rest []byte) {
|
||||
// start begins with a newline. However, at the very beginning of
|
||||
// the byte array, we'll accept the start string without it.
|
||||
rest = data
|
||||
if bytes.HasPrefix(data, start[1:]) {
|
||||
rest = rest[len(start)-1:]
|
||||
} else if i := bytes.Index(data, start); i >= 0 {
|
||||
rest = rest[i+len(start):]
|
||||
} else {
|
||||
return nil, data
|
||||
}
|
||||
|
||||
// Consume the start line and check it does not have a suffix.
|
||||
suffix, rest := getLine(rest)
|
||||
if len(suffix) != 0 {
|
||||
return nil, data
|
||||
}
|
||||
|
||||
var line []byte
|
||||
b = &Block{
|
||||
Headers: make(textproto.MIMEHeader),
|
||||
}
|
||||
|
||||
// Next come a series of header lines.
|
||||
for {
|
||||
// This loop terminates because getLine's second result is
|
||||
// always smaller than its argument.
|
||||
if len(rest) == 0 {
|
||||
return nil, data
|
||||
}
|
||||
// An empty line marks the end of the headers.
|
||||
if line, rest = getLine(rest); len(line) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Reject headers with control or Unicode characters.
|
||||
if i := bytes.IndexFunc(line, func(r rune) bool {
|
||||
return r < 0x20 || r > 0x7e
|
||||
}); i != -1 {
|
||||
return nil, data
|
||||
}
|
||||
|
||||
i := bytes.Index(line, []byte{':'})
|
||||
if i == -1 {
|
||||
return nil, data
|
||||
}
|
||||
|
||||
key, val := string(line[0:i]), string(line[i+1:])
|
||||
key = strings.TrimSpace(key)
|
||||
if key != "Hash" {
|
||||
return nil, data
|
||||
}
|
||||
val = strings.TrimSpace(val)
|
||||
b.Headers.Add(key, val)
|
||||
}
|
||||
|
||||
firstLine := true
|
||||
for {
|
||||
start := rest
|
||||
|
||||
line, rest = getLine(rest)
|
||||
if len(line) == 0 && len(rest) == 0 {
|
||||
// No armored data was found, so this isn't a complete message.
|
||||
return nil, data
|
||||
}
|
||||
if bytes.Equal(line, endText) {
|
||||
// Back up to the start of the line because armor expects to see the
|
||||
// header line.
|
||||
rest = start
|
||||
break
|
||||
}
|
||||
|
||||
// The final CRLF isn't included in the hash so we don't write it until
|
||||
// we've seen the next line.
|
||||
if firstLine {
|
||||
firstLine = false
|
||||
} else {
|
||||
b.Bytes = append(b.Bytes, crlf...)
|
||||
}
|
||||
|
||||
if bytes.HasPrefix(line, dashEscape) {
|
||||
line = line[2:]
|
||||
}
|
||||
line = bytes.TrimRight(line, " \t")
|
||||
b.Bytes = append(b.Bytes, line...)
|
||||
|
||||
b.Plaintext = append(b.Plaintext, line...)
|
||||
b.Plaintext = append(b.Plaintext, lf)
|
||||
}
|
||||
|
||||
// We want to find the extent of the armored data (including any newlines at
|
||||
// the end).
|
||||
i := bytes.Index(rest, end)
|
||||
if i == -1 {
|
||||
return nil, data
|
||||
}
|
||||
i += len(end)
|
||||
for i < len(rest) && (rest[i] == '\r' || rest[i] == '\n') {
|
||||
i++
|
||||
}
|
||||
armored := rest[:i]
|
||||
rest = rest[i:]
|
||||
|
||||
var err error
|
||||
b.ArmoredSignature, err = armor.Decode(bytes.NewBuffer(armored))
|
||||
if err != nil {
|
||||
return nil, data
|
||||
}
|
||||
|
||||
return b, rest
|
||||
}
|
||||
|
||||
// A dashEscaper is an io.WriteCloser which processes the body of a clear-signed
|
||||
// message. The clear-signed message is written to buffered and a hash, suitable
|
||||
// for signing, is maintained in h.
|
||||
//
|
||||
// When closed, an armored signature is created and written to complete the
|
||||
// message.
|
||||
type dashEscaper struct {
|
||||
buffered *bufio.Writer
|
||||
hashers []hash.Hash // one per key in privateKeys
|
||||
hashType crypto.Hash
|
||||
toHash io.Writer // writes to all the hashes in hashers
|
||||
|
||||
atBeginningOfLine bool
|
||||
isFirstLine bool
|
||||
|
||||
whitespace []byte
|
||||
byteBuf []byte // a one byte buffer to save allocations
|
||||
|
||||
privateKeys []*packet.PrivateKey
|
||||
config *packet.Config
|
||||
}
|
||||
|
||||
func (d *dashEscaper) Write(data []byte) (n int, err error) {
|
||||
for _, b := range data {
|
||||
d.byteBuf[0] = b
|
||||
|
||||
if d.atBeginningOfLine {
|
||||
// The final CRLF isn't included in the hash so we have to wait
|
||||
// until this point (the start of the next line) before writing it.
|
||||
if !d.isFirstLine {
|
||||
d.toHash.Write(crlf)
|
||||
}
|
||||
d.isFirstLine = false
|
||||
}
|
||||
|
||||
// Any whitespace at the end of the line has to be removed so we
|
||||
// buffer it until we find out whether there's more on this line.
|
||||
if b == ' ' || b == '\t' || b == '\r' {
|
||||
d.whitespace = append(d.whitespace, b)
|
||||
d.atBeginningOfLine = false
|
||||
continue
|
||||
}
|
||||
|
||||
if d.atBeginningOfLine {
|
||||
// At the beginning of a line, hyphens have to be escaped.
|
||||
if b == '-' {
|
||||
// The signature isn't calculated over the dash-escaped text so
|
||||
// the escape is only written to buffered.
|
||||
if _, err = d.buffered.Write(dashEscape); err != nil {
|
||||
return
|
||||
}
|
||||
d.toHash.Write(d.byteBuf)
|
||||
d.atBeginningOfLine = false
|
||||
} else if b == '\n' {
|
||||
// Nothing to do because we delay writing CRLF to the hash.
|
||||
} else {
|
||||
d.toHash.Write(d.byteBuf)
|
||||
d.atBeginningOfLine = false
|
||||
}
|
||||
if err = d.buffered.WriteByte(b); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if b == '\n' {
|
||||
// We got a raw \n. Drop any trailing whitespace and write a
|
||||
// CRLF.
|
||||
d.whitespace = d.whitespace[:0]
|
||||
// We delay writing CRLF to the hash until the start of the
|
||||
// next line.
|
||||
if err = d.buffered.WriteByte(b); err != nil {
|
||||
return
|
||||
}
|
||||
d.atBeginningOfLine = true
|
||||
} else {
|
||||
// Any buffered whitespace wasn't at the end of the line so
|
||||
// we need to write it out.
|
||||
if len(d.whitespace) > 0 {
|
||||
d.toHash.Write(d.whitespace)
|
||||
if _, err = d.buffered.Write(d.whitespace); err != nil {
|
||||
return
|
||||
}
|
||||
d.whitespace = d.whitespace[:0]
|
||||
}
|
||||
d.toHash.Write(d.byteBuf)
|
||||
if err = d.buffered.WriteByte(b); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = len(data)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *dashEscaper) Close() (err error) {
|
||||
if !d.atBeginningOfLine {
|
||||
if err = d.buffered.WriteByte(lf); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t := d.config.Now()
|
||||
for i, k := range d.privateKeys {
|
||||
sig := new(packet.Signature)
|
||||
sig.SigType = packet.SigTypeText
|
||||
sig.PubKeyAlgo = k.PubKeyAlgo
|
||||
sig.Hash = d.hashType
|
||||
sig.CreationTime = t
|
||||
sig.IssuerKeyId = &k.KeyId
|
||||
|
||||
if err = sig.Sign(d.hashers[i], k, d.config); err != nil {
|
||||
return
|
||||
}
|
||||
if err = sig.Serialize(out); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = out.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = d.buffered.Flush(); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Encode returns a WriteCloser which will clear-sign a message with privateKey
|
||||
// and write it to w. If config is nil, sensible defaults are used.
|
||||
func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
|
||||
return EncodeMulti(w, []*packet.PrivateKey{privateKey}, config)
|
||||
}
|
||||
|
||||
// EncodeMulti returns a WriteCloser which will clear-sign a message with all the
|
||||
// private keys indicated and write it to w. If config is nil, sensible defaults
|
||||
// are used.
|
||||
func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
|
||||
for _, k := range privateKeys {
|
||||
if k.Encrypted {
|
||||
return nil, errors.InvalidArgumentError(fmt.Sprintf("signing key %s is encrypted", k.KeyIdString()))
|
||||
}
|
||||
}
|
||||
|
||||
hashType := config.Hash()
|
||||
name := nameOfHash(hashType)
|
||||
if len(name) == 0 {
|
||||
return nil, errors.UnsupportedError("unknown hash type: " + strconv.Itoa(int(hashType)))
|
||||
}
|
||||
|
||||
if !hashType.Available() {
|
||||
return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType)))
|
||||
}
|
||||
var hashers []hash.Hash
|
||||
var ws []io.Writer
|
||||
for range privateKeys {
|
||||
h := hashType.New()
|
||||
hashers = append(hashers, h)
|
||||
ws = append(ws, h)
|
||||
}
|
||||
toHash := io.MultiWriter(ws...)
|
||||
|
||||
buffered := bufio.NewWriter(w)
|
||||
// start has a \n at the beginning that we don't want here.
|
||||
if _, err = buffered.Write(start[1:]); err != nil {
|
||||
return
|
||||
}
|
||||
if err = buffered.WriteByte(lf); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = buffered.WriteString("Hash: "); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = buffered.WriteString(name); err != nil {
|
||||
return
|
||||
}
|
||||
if err = buffered.WriteByte(lf); err != nil {
|
||||
return
|
||||
}
|
||||
if err = buffered.WriteByte(lf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
plaintext = &dashEscaper{
|
||||
buffered: buffered,
|
||||
hashers: hashers,
|
||||
hashType: hashType,
|
||||
toHash: toHash,
|
||||
|
||||
atBeginningOfLine: true,
|
||||
isFirstLine: true,
|
||||
|
||||
byteBuf: make([]byte, 1),
|
||||
|
||||
privateKeys: privateKeys,
|
||||
config: config,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// nameOfHash returns the OpenPGP name for the given hash, or the empty string
|
||||
// if the name isn't known. See RFC 4880, section 9.4.
|
||||
func nameOfHash(h crypto.Hash) string {
|
||||
switch h {
|
||||
case crypto.MD5:
|
||||
return "MD5"
|
||||
case crypto.SHA1:
|
||||
return "SHA1"
|
||||
case crypto.RIPEMD160:
|
||||
return "RIPEMD160"
|
||||
case crypto.SHA224:
|
||||
return "SHA224"
|
||||
case crypto.SHA256:
|
||||
return "SHA256"
|
||||
case crypto.SHA384:
|
||||
return "SHA384"
|
||||
case crypto.SHA512:
|
||||
return "SHA512"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
398
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
generated
vendored
Normal file
398
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
generated
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package clearsign
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
func testParse(t *testing.T, input []byte, expected, expectedPlaintext string) {
|
||||
b, rest := Decode(input)
|
||||
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)
|
||||
}
|
||||
if !bytes.Equal(b.Bytes, []byte(expected)) {
|
||||
t.Errorf("bad body, got:%x want:%x", b.Bytes, expected)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b.Plaintext, []byte(expectedPlaintext)) {
|
||||
t.Errorf("bad plaintext, got:%x want:%x", b.Plaintext, expectedPlaintext)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
testParse(t, clearsignInput, "Hello world\r\nline 2", "Hello world\nline 2\n")
|
||||
testParse(t, clearsignInput2, "\r\n\r\n(This message has a couple of blank lines at the start and end.)\r\n\r\n", "\n\n(This message has a couple of blank lines at the start and end.)\n\n\n")
|
||||
}
|
||||
|
||||
func TestParseWithNoNewlineAtEnd(t *testing.T) {
|
||||
input := clearsignInput
|
||||
input = input[:len(input)-len("trailing")-1]
|
||||
b, rest := Decode(input)
|
||||
if b == nil {
|
||||
t.Fatal("failed to decode clearsign message")
|
||||
}
|
||||
if len(rest) > 0 {
|
||||
t.Errorf("unexpected remaining bytes returned: %s", string(rest))
|
||||
}
|
||||
}
|
||||
|
||||
var signingTests = []struct {
|
||||
in, signed, plaintext string
|
||||
}{
|
||||
{"", "", ""},
|
||||
{"a", "a", "a\n"},
|
||||
{"a\n", "a", "a\n"},
|
||||
{"-a\n", "-a", "-a\n"},
|
||||
{"--a\nb", "--a\r\nb", "--a\nb\n"},
|
||||
// leading whitespace
|
||||
{" a\n", " a", " a\n"},
|
||||
{" a\n", " a", " a\n"},
|
||||
// trailing whitespace (should be stripped)
|
||||
{"a \n", "a", "a\n"},
|
||||
{"a ", "a", "a\n"},
|
||||
// whitespace-only lines (should be stripped)
|
||||
{" \n", "", "\n"},
|
||||
{" ", "", "\n"},
|
||||
{"a\n \n \nb\n", "a\r\n\r\n\r\nb", "a\n\n\nb\n"},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We use this to make test keys, so that they aren't all the same.
|
||||
type quickRand byte
|
||||
|
||||
func (qr *quickRand) Read(p []byte) (int, error) {
|
||||
for i := range p {
|
||||
p[i] = byte(*qr)
|
||||
}
|
||||
*qr++
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func TestMultiSign(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping long test in -short mode")
|
||||
}
|
||||
|
||||
zero := quickRand(0)
|
||||
config := packet.Config{Rand: &zero}
|
||||
|
||||
for nKeys := 0; nKeys < 4; nKeys++ {
|
||||
nextTest:
|
||||
for nExtra := 0; nExtra < 4; nExtra++ {
|
||||
var signKeys []*packet.PrivateKey
|
||||
var verifyKeys openpgp.EntityList
|
||||
|
||||
desc := fmt.Sprintf("%d keys; %d of which will be used to verify", nKeys+nExtra, nKeys)
|
||||
for i := 0; i < nKeys+nExtra; i++ {
|
||||
e, err := openpgp.NewEntity("name", "comment", "email", &config)
|
||||
if err != nil {
|
||||
t.Errorf("cannot create key: %v", err)
|
||||
continue nextTest
|
||||
}
|
||||
if i < nKeys {
|
||||
verifyKeys = append(verifyKeys, e)
|
||||
}
|
||||
signKeys = append(signKeys, e.PrivateKey)
|
||||
}
|
||||
|
||||
input := []byte("this is random text\r\n4 17")
|
||||
var output bytes.Buffer
|
||||
w, err := EncodeMulti(&output, signKeys, nil)
|
||||
if err != nil {
|
||||
t.Errorf("EncodeMulti (%s) failed: %v", desc, err)
|
||||
}
|
||||
if _, err := w.Write(input); err != nil {
|
||||
t.Errorf("Write(%q) to signer (%s) failed: %v", string(input), desc, err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Errorf("Close() of signer (%s) failed: %v", desc, err)
|
||||
}
|
||||
|
||||
block, _ := Decode(output.Bytes())
|
||||
if string(block.Bytes) != string(input) {
|
||||
t.Errorf("Inline data didn't match original; got %q want %q", string(block.Bytes), string(input))
|
||||
}
|
||||
_, err = openpgp.CheckDetachedSignature(verifyKeys, bytes.NewReader(block.Bytes), block.ArmoredSignature.Body)
|
||||
if nKeys == 0 {
|
||||
if err == nil {
|
||||
t.Errorf("verifying inline (%s) succeeded; want failure", desc)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("verifying inline (%s) failed (%v); want success", desc, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeMissingCRC(t *testing.T) {
|
||||
block, rest := Decode(clearsignInput3)
|
||||
if block == nil {
|
||||
t.Fatal("failed to decode PGP signature missing a CRC")
|
||||
}
|
||||
if len(rest) > 0 {
|
||||
t.Fatalf("Decode should not have any remaining data left: %s", rest)
|
||||
}
|
||||
if _, err := packet.Read(block.ArmoredSignature.Body); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := packet.Read(block.ArmoredSignature.Body); err != io.EOF {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
const signatureBlock = `
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: OpenPrivacy 0.99
|
||||
|
||||
yDgBO22WxBHv7O8X7O/jygAEzol56iUKiXmV+XmpCtmpqQUKiQrFqclFqUDBovzS
|
||||
vBSFjNSiVHsuAA==
|
||||
=njUN
|
||||
-----END PGP SIGNATURE-----
|
||||
`
|
||||
|
||||
var invalidInputs = []string{
|
||||
`
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA256
|
||||
|
||||
(This message was truncated.)
|
||||
`,
|
||||
`
|
||||
-----BEGIN PGP SIGNED MESSAGE-----garbage
|
||||
Hash: SHA256
|
||||
|
||||
_o/
|
||||
` + signatureBlock,
|
||||
`
|
||||
garbage-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA256
|
||||
|
||||
_o/
|
||||
` + signatureBlock,
|
||||
`
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA` + "\x0b\x0b" + `256
|
||||
|
||||
_o/
|
||||
` + signatureBlock,
|
||||
`
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
NotHash: SHA256
|
||||
|
||||
_o/
|
||||
` + signatureBlock,
|
||||
}
|
||||
|
||||
func TestParseInvalid(t *testing.T) {
|
||||
for i, input := range invalidInputs {
|
||||
if b, rest := Decode([]byte(input)); b != nil {
|
||||
t.Errorf("#%d: decoded a bad clearsigned message without any error", i)
|
||||
} else if string(rest) != input {
|
||||
t.Errorf("#%d: did not return all data with a bad message", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var clearsignInput = []byte(`
|
||||
;lasjlkfdsa
|
||||
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
Hello world
|
||||
line 2
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.10 (GNU/Linux)
|
||||
|
||||
iJwEAQECAAYFAk8kMuEACgkQO9o98PRieSpMsAQAhmY/vwmNpflrPgmfWsYhk5O8
|
||||
pjnBUzZwqTDoDeINjZEoPDSpQAHGhjFjgaDx/Gj4fAl0dM4D0wuUEBb6QOrwflog
|
||||
2A2k9kfSOMOtk0IH/H5VuFN1Mie9L/erYXjTQIptv9t9J7NoRBMU0QOOaFU0JaO9
|
||||
MyTpno24AjIAGb+mH1U=
|
||||
=hIJ6
|
||||
-----END PGP SIGNATURE-----
|
||||
trailing`)
|
||||
|
||||
var clearsignInput2 = []byte(`
|
||||
asdlfkjasdlkfjsadf
|
||||
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA256
|
||||
|
||||
|
||||
|
||||
(This message has a couple of blank lines at the start and end.)
|
||||
|
||||
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.11 (GNU/Linux)
|
||||
|
||||
iJwEAQEIAAYFAlPpSREACgkQO9o98PRieSpZTAP+M8QUoCt/7Rf3YbXPcdzIL32v
|
||||
pt1I+cMNeopzfLy0u4ioEFi8s5VkwpL1AFmirvgViCwlf82inoRxzZRiW05JQ5LI
|
||||
ESEzeCoy2LIdRCQ2hcrG8pIUPzUO4TqO5D/dMbdHwNH4h5nNmGJUAEG6FpURlPm+
|
||||
qZg6BaTvOxepqOxnhVU=
|
||||
=e+C6
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
trailing`)
|
||||
|
||||
var clearsignInput3 = []byte(`-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA256
|
||||
|
||||
Origin: vscode stable
|
||||
Label: vscode stable
|
||||
Suite: stable
|
||||
Codename: stable
|
||||
Date: Mon, 13 Jan 2020 08:41:45 UTC
|
||||
Architectures: amd64
|
||||
Components: main
|
||||
Description: Generated by aptly
|
||||
MD5Sum:
|
||||
66437152b3082616d8053e52c4bafafb 5821166 Contents-amd64
|
||||
8024662ed51109946a517754bbafdd33 286298 Contents-amd64.gz
|
||||
66437152b3082616d8053e52c4bafafb 5821166 main/Contents-amd64
|
||||
8024662ed51109946a517754bbafdd33 286298 main/Contents-amd64.gz
|
||||
3062a08b3eca94a65d6d17ba1dafcf3e 1088265 main/binary-amd64/Packages
|
||||
b8ee22200fba8fa3be56c1ff946cdd24 159344 main/binary-amd64/Packages.bz2
|
||||
f89c47c81ebd25caf287c8e6dda16c1a 169456 main/binary-amd64/Packages.gz
|
||||
4c9ca25b556f111a5536c78df885ad82 95 main/binary-amd64/Release
|
||||
SHA1:
|
||||
2b62d0e322746b7d094878278f49993ca4314bf7 5821166 Contents-amd64
|
||||
aafe35cce12e03d8b1939e403ddf5c0958c6e9bd 286298 Contents-amd64.gz
|
||||
2b62d0e322746b7d094878278f49993ca4314bf7 5821166 main/Contents-amd64
|
||||
aafe35cce12e03d8b1939e403ddf5c0958c6e9bd 286298 main/Contents-amd64.gz
|
||||
30316ac5d4ce3b472a96a797eeb0a2a82d43ed3e 1088265 main/binary-amd64/Packages
|
||||
6507e0b4da8194fd1048fcbb74c6e7433edaf3d6 159344 main/binary-amd64/Packages.bz2
|
||||
ec9d39c39567c74001221e4900fb5d11ec11b833 169456 main/binary-amd64/Packages.gz
|
||||
58bf20987a91d35936f18efce75ea233d43dbf8b 95 main/binary-amd64/Release
|
||||
SHA256:
|
||||
deff9ebfc44bf482e10a6ea10f608c6bb0fdc8373bf86b88cad9d99879ae3c39 5821166 Contents-amd64
|
||||
f163bc65c7666ef58e0be3336e8c846ae2b7b388fbb2d7db0bcdc3fd1abae462 286298 Contents-amd64.gz
|
||||
deff9ebfc44bf482e10a6ea10f608c6bb0fdc8373bf86b88cad9d99879ae3c39 5821166 main/Contents-amd64
|
||||
f163bc65c7666ef58e0be3336e8c846ae2b7b388fbb2d7db0bcdc3fd1abae462 286298 main/Contents-amd64.gz
|
||||
0fba50799ef72d0c2b354d0bcbbc8c623f6dae5a7fd7c218a54ea44dd8a49d5e 1088265 main/binary-amd64/Packages
|
||||
69382470a88b67acde80fe45ab223016adebc445713ff0aa3272902581d21f13 159344 main/binary-amd64/Packages.bz2
|
||||
1724b8ace5bd8882943e9463d8525006f33ca704480da0186fd47937451dc216 169456 main/binary-amd64/Packages.gz
|
||||
0f509a0cb07e0ab433176fa47a21dccccc6b519f25f640cc58561104c11de6c2 95 main/binary-amd64/Release
|
||||
SHA512:
|
||||
f69f09c6180ceb6625a84b5f7123ad27972983146979dcfd9c38b2990459b52b4975716f85374511486bb5ad5852ebb1ef8265176df7134fc15b17ada3ba596c 5821166 Contents-amd64
|
||||
46031bf89166188989368957d20cdcaac6eec72bab3f9839c9704bb08cbee3174ca6da11e290b0eab0e6b5754c1e7feb06d18ec9c5a0c955029cef53235e0a3a 286298 Contents-amd64.gz
|
||||
f69f09c6180ceb6625a84b5f7123ad27972983146979dcfd9c38b2990459b52b4975716f85374511486bb5ad5852ebb1ef8265176df7134fc15b17ada3ba596c 5821166 main/Contents-amd64
|
||||
46031bf89166188989368957d20cdcaac6eec72bab3f9839c9704bb08cbee3174ca6da11e290b0eab0e6b5754c1e7feb06d18ec9c5a0c955029cef53235e0a3a 286298 main/Contents-amd64.gz
|
||||
3f78baf5adbaf0100996555b154807c794622fd0b5879b568ae0b6560e988fbfabed8d97db5a703d1a58514b9690fc6b60f9ad2eeece473d86ab257becd0ae41 1088265 main/binary-amd64/Packages
|
||||
18f26df90beff29192662ca40525367c3c04f4581d59d2e9ab1cd0700a145b6a292a1609ca33ebe1c211f13718a8eee751f41fd8189cf93d52aa3e0851542dfc 159344 main/binary-amd64/Packages.bz2
|
||||
6a6d917229e0cf06c493e174a87d76e815717676f2c70bcbd3bc689a80bd3c5489ea97db83b8f74cba8e70f374f9d9974f22b1ed2687a4ba1dacd22fdef7e14d 169456 main/binary-amd64/Packages.gz
|
||||
e1a4378ad266c13c2edf8a0e590fa4d11973ab99ce79f15af005cb838f1600f66f3dc6da8976fa8b474da9073c118039c27623ab3360c6df115071497fe4f50c 95 main/binary-amd64/Release
|
||||
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: BSN Pgp v1.0.0.0
|
||||
|
||||
iQEcBAEBCAAGBQJeHC1bAAoJEOs+lK2+EinPAg8H/1rrhcgfm1HYL+Vmr9Ns6ton
|
||||
LWQ8r13ADN66UTRa3XsO9V+q1fYowTqpXq6EZt2Gmlby/cpDf7mFPM5IteOXWLl7
|
||||
QcWxPKHcdPIUi+h5F7BkFW65imP9GyX+V5Pxx5X544op7hYKaI0gAQ1oYtWDb3HE
|
||||
4D27fju6icbj8w6E8TePcrDn82UvWAcaI5WSLboyhXCt2DxS3PNGFlyaP58zKJ8F
|
||||
9cbBzksuMgMaTPAAMrU0zrFGfGeQz0Yo6nV/gRGiQaL9pSeIJWSKLNCMG/nIGmv2
|
||||
xHVNFqTEetREY6UcQmuhwOn4HezyigH6XCBVp/Uez1izXiNdwBOet34SSvnkuJ4=
|
||||
-----END PGP SIGNATURE-----`)
|
||||
|
||||
var signingKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Version: GnuPG v1.4.10 (GNU/Linux)
|
||||
|
||||
lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
|
||||
idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
|
||||
vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
|
||||
AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
|
||||
0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
|
||||
IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
|
||||
VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
|
||||
gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
|
||||
TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
|
||||
q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
|
||||
dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
|
||||
CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
|
||||
ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
|
||||
eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
|
||||
AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
|
||||
bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
|
||||
/UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
|
||||
A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
|
||||
TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
|
||||
lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
|
||||
rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
|
||||
oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
|
||||
QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
|
||||
nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
|
||||
AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
|
||||
BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
|
||||
AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
|
||||
VrM0m72/jnpKo04=
|
||||
=zNCn
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
`
|
||||
Reference in New Issue
Block a user