summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/crypto/openpgp/clearsign
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/openpgp/clearsign')
-rw-r--r--vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go376
-rw-r--r--vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go210
2 files changed, 586 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
new file mode 100644
index 000000000..def4cabaf
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
@@ -0,0 +1,376 @@
+// 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"
+ "hash"
+ "io"
+ "net/textproto"
+ "strconv"
+
+ "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 message 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.
+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.
+ _, rest = getLine(rest)
+
+ 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
+ }
+
+ i := bytes.Index(line, []byte{':'})
+ if i == -1 {
+ return nil, data
+ }
+
+ key, val := line[0:i], line[i+1:]
+ key = bytes.TrimSpace(key)
+ val = bytes.TrimSpace(val)
+ b.Headers.Add(string(key), string(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
+ h hash.Hash
+ hashType crypto.Hash
+
+ atBeginningOfLine bool
+ isFirstLine bool
+
+ whitespace []byte
+ byteBuf []byte // a one byte buffer to save allocations
+
+ privateKey *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.h.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.h.Write(d.byteBuf)
+ d.atBeginningOfLine = false
+ } else if b == '\n' {
+ // Nothing to do because we delay writing CRLF to the hash.
+ } else {
+ d.h.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.h.Write(d.whitespace)
+ if _, err = d.buffered.Write(d.whitespace); err != nil {
+ return
+ }
+ d.whitespace = d.whitespace[:0]
+ }
+ d.h.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
+ }
+ }
+ sig := new(packet.Signature)
+ sig.SigType = packet.SigTypeText
+ sig.PubKeyAlgo = d.privateKey.PubKeyAlgo
+ sig.Hash = d.hashType
+ sig.CreationTime = d.config.Now()
+ sig.IssuerKeyId = &d.privateKey.KeyId
+
+ if err = sig.Sign(d.h, d.privateKey, d.config); err != nil {
+ return
+ }
+
+ out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil)
+ if 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) {
+ if privateKey.Encrypted {
+ return nil, errors.InvalidArgumentError("signing key is encrypted")
+ }
+
+ 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)))
+ }
+ h := hashType.New()
+
+ 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,
+ h: h,
+ hashType: hashType,
+
+ atBeginningOfLine: true,
+ isFirstLine: true,
+
+ byteBuf: make([]byte, 1),
+
+ privateKey: privateKey,
+ 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 ""
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
new file mode 100644
index 000000000..2c0948078
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
@@ -0,0 +1,210 @@
+// 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"
+ "golang.org/x/crypto/openpgp"
+ "testing"
+)
+
+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 TestParseInvalid(t *testing.T) {
+ if b, _ := Decode(clearsignInput3); b != nil {
+ t.Fatal("decoded a bad clearsigned message without any error")
+ }
+}
+
+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)
+ }
+ }
+}
+
+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
+
+(This message was truncated.)
+`)
+
+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-----
+`