golang.org/x/crypto: update to latest version.

Change-Id: I7362caf23b7cf99fcdbbbafbe2028b570c31eb1c
diff --git a/go/src/golang.org/x/crypto/.gitattributes b/go/src/golang.org/x/crypto/.gitattributes
new file mode 100644
index 0000000..d2f212e
--- /dev/null
+++ b/go/src/golang.org/x/crypto/.gitattributes
@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text
diff --git a/go/src/golang.org/x/crypto/CONTRIBUTING.md b/go/src/golang.org/x/crypto/CONTRIBUTING.md
new file mode 100644
index 0000000..88dff59
--- /dev/null
+++ b/go/src/golang.org/x/crypto/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+
+## Filing issues
+
+When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
+
+1. What version of Go are you using (`go version`)?
+2. What operating system and processor architecture are you using?
+3. What did you do?
+4. What did you expect to see?
+5. What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+**We do not accept GitHub pull requests**
+(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.
+
diff --git a/go/src/golang.org/x/crypto/README.google b/go/src/golang.org/x/crypto/README.google
index 4b39bd8..2fd2c7f 100644
--- a/go/src/golang.org/x/crypto/README.google
+++ b/go/src/golang.org/x/crypto/README.google
@@ -1,5 +1,5 @@
-URL: https://go.googlesource.com/crypto/+archive/632d287f9f3f54b09809eebbd3cacbcb00b9f2fc.tar.gz
-Version: 632d287f9f3f54b09809eebbd3cacbcb00b9f2fc
+URL: https://go.googlesource.com/crypto/+archive/02a186af8b62cb007f392270669b91be5527d39c.tar.gz
+Version: 602a186af8b62cb007f392270669b91be5527d39c
 License: New BSD
 License File: LICENSE
 
diff --git a/go/src/golang.org/x/crypto/codereview.cfg b/go/src/golang.org/x/crypto/codereview.cfg
new file mode 100644
index 0000000..3f8b14b
--- /dev/null
+++ b/go/src/golang.org/x/crypto/codereview.cfg
@@ -0,0 +1 @@
+issuerepo: golang/go
diff --git a/go/src/golang.org/x/crypto/curve25519/const_amd64.s b/go/src/golang.org/x/crypto/curve25519/const_amd64.s
index 0517fc1..797f9b0 100644
--- a/go/src/golang.org/x/crypto/curve25519/const_amd64.s
+++ b/go/src/golang.org/x/crypto/curve25519/const_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF
 GLOBL ·REDMASK51(SB), 8, $8
diff --git a/go/src/golang.org/x/crypto/curve25519/cswap_amd64.s b/go/src/golang.org/x/crypto/curve25519/cswap_amd64.s
index 16204ed..45484d1 100644
--- a/go/src/golang.org/x/crypto/curve25519/cswap_amd64.s
+++ b/go/src/golang.org/x/crypto/curve25519/cswap_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 // func cswap(inout *[5]uint64, v uint64)
 TEXT ·cswap(SB),7,$0
diff --git a/go/src/golang.org/x/crypto/curve25519/curve25519.go b/go/src/golang.org/x/crypto/curve25519/curve25519.go
index 5b7b9bc..6918c47 100644
--- a/go/src/golang.org/x/crypto/curve25519/curve25519.go
+++ b/go/src/golang.org/x/crypto/curve25519/curve25519.go
@@ -4,7 +4,7 @@
 
 // We have a implementation in amd64 assembly so this code is only run on
 // non-amd64 platforms. The amd64 assembly does not support gccgo.
-// +build !amd64 gccgo
+// +build !amd64 gccgo appengine
 
 package curve25519
 
diff --git a/go/src/golang.org/x/crypto/curve25519/freeze_amd64.s b/go/src/golang.org/x/crypto/curve25519/freeze_amd64.s
index 0b80eef..37599fa 100644
--- a/go/src/golang.org/x/crypto/curve25519/freeze_amd64.s
+++ b/go/src/golang.org/x/crypto/curve25519/freeze_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 // func freeze(inout *[5]uint64)
 TEXT ·freeze(SB),7,$96-8
diff --git a/go/src/golang.org/x/crypto/curve25519/ladderstep_amd64.s b/go/src/golang.org/x/crypto/curve25519/ladderstep_amd64.s
index 10bb89f..3949f9c 100644
--- a/go/src/golang.org/x/crypto/curve25519/ladderstep_amd64.s
+++ b/go/src/golang.org/x/crypto/curve25519/ladderstep_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 // func ladderstep(inout *[5][5]uint64)
 TEXT ·ladderstep(SB),0,$384-8
diff --git a/go/src/golang.org/x/crypto/curve25519/mont25519_amd64.go b/go/src/golang.org/x/crypto/curve25519/mont25519_amd64.go
index 3275877..5822bd5 100644
--- a/go/src/golang.org/x/crypto/curve25519/mont25519_amd64.go
+++ b/go/src/golang.org/x/crypto/curve25519/mont25519_amd64.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 package curve25519
 
diff --git a/go/src/golang.org/x/crypto/curve25519/mul_amd64.s b/go/src/golang.org/x/crypto/curve25519/mul_amd64.s
index 5404f32..e48d183 100644
--- a/go/src/golang.org/x/crypto/curve25519/mul_amd64.s
+++ b/go/src/golang.org/x/crypto/curve25519/mul_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 // func mul(dest, a, b *[5]uint64)
 TEXT ·mul(SB),0,$128-24
diff --git a/go/src/golang.org/x/crypto/curve25519/square_amd64.s b/go/src/golang.org/x/crypto/curve25519/square_amd64.s
index cb0053f..78d1a50 100644
--- a/go/src/golang.org/x/crypto/curve25519/square_amd64.s
+++ b/go/src/golang.org/x/crypto/curve25519/square_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 // func square(out, in *[5]uint64)
 TEXT ·square(SB),7,$96-16
diff --git a/go/src/golang.org/x/crypto/ocsp/ocsp.go b/go/src/golang.org/x/crypto/ocsp/ocsp.go
index 0252b58..602fefa 100644
--- a/go/src/golang.org/x/crypto/ocsp/ocsp.go
+++ b/go/src/golang.org/x/crypto/ocsp/ocsp.go
@@ -9,10 +9,15 @@
 
 import (
 	"crypto"
-	_ "crypto/sha1"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha1"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"encoding/asn1"
+	"errors"
 	"math/big"
 	"time"
 )
@@ -38,6 +43,21 @@
 	SerialNumber  *big.Int
 }
 
+// https://tools.ietf.org/html/rfc2560#section-4.1.1
+type ocspRequest struct {
+	TBSRequest tbsRequest
+}
+
+type tbsRequest struct {
+	Version       int              `asn1:"explicit,tag:0,default:0,optional"`
+	RequestorName pkix.RDNSequence `asn1:"explicit,tag:1,optional"`
+	RequestList   []request
+}
+
+type request struct {
+	Cert certID
+}
+
 type responseASN1 struct {
 	Status   asn1.Enumerated
 	Response responseBytes `asn1:"explicit,tag:0"`
@@ -56,26 +76,26 @@
 }
 
 type responseData struct {
-	Raw           asn1.RawContent
-	Version       int              `asn1:"optional,default:1,explicit,tag:0"`
-	RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
-	KeyHash       []byte           `asn1:"optional,explicit,tag:2"`
-	ProducedAt    time.Time
-	Responses     []singleResponse
+	Raw              asn1.RawContent
+	Version          int           `asn1:"optional,default:1,explicit,tag:0"`
+	RawResponderName asn1.RawValue `asn1:"optional,explicit,tag:1"`
+	KeyHash          []byte        `asn1:"optional,explicit,tag:2"`
+	ProducedAt       time.Time     `asn1:"generalized"`
+	Responses        []singleResponse
 }
 
 type singleResponse struct {
 	CertID     certID
-	Good       asn1.Flag   `asn1:"explicit,tag:0,optional"`
+	Good       asn1.Flag   `asn1:"tag:0,optional"`
 	Revoked    revokedInfo `asn1:"explicit,tag:1,optional"`
-	Unknown    asn1.Flag   `asn1:"explicit,tag:2,optional"`
-	ThisUpdate time.Time
-	NextUpdate time.Time `asn1:"explicit,tag:0,optional"`
+	Unknown    asn1.Flag   `asn1:"tag:2,optional"`
+	ThisUpdate time.Time   `asn1:"generalized"`
+	NextUpdate time.Time   `asn1:"generalized,explicit,tag:0,optional"`
 }
 
 type revokedInfo struct {
-	RevocationTime time.Time
-	Reason         int `asn1:"explicit,tag:0,optional"`
+	RevocationTime time.Time `asn1:"generalized"`
+	Reason         int       `asn1:"explicit,tag:0,optional"`
 }
 
 var (
@@ -93,38 +113,121 @@
 	oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
 )
 
+var hashOIDs = map[crypto.Hash]asn1.ObjectIdentifier{
+	crypto.SHA1:   asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}),
+	crypto.SHA256: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1}),
+	crypto.SHA384: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 2}),
+	crypto.SHA512: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 3}),
+}
+
+// TODO(rlb): This is also from crypto/x509, so same comment as AGL's below
+var signatureAlgorithmDetails = []struct {
+	algo       x509.SignatureAlgorithm
+	oid        asn1.ObjectIdentifier
+	pubKeyAlgo x509.PublicKeyAlgorithm
+	hash       crypto.Hash
+}{
+	{x509.MD2WithRSA, oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
+	{x509.MD5WithRSA, oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
+	{x509.SHA1WithRSA, oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
+	{x509.SHA256WithRSA, oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
+	{x509.SHA384WithRSA, oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
+	{x509.SHA512WithRSA, oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
+	{x509.DSAWithSHA1, oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
+	{x509.DSAWithSHA256, oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
+	{x509.ECDSAWithSHA1, oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
+	{x509.ECDSAWithSHA256, oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
+	{x509.ECDSAWithSHA384, oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
+	{x509.ECDSAWithSHA512, oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
+}
+
+// TODO(rlb): This is also from crypto/x509, so same comment as AGL's below
+func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+	var pubType x509.PublicKeyAlgorithm
+
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
+		pubType = x509.RSA
+		hashFunc = crypto.SHA256
+		sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+		sigAlgo.Parameters = asn1.RawValue{
+			Tag: 5,
+		}
+
+	case *ecdsa.PublicKey:
+		pubType = x509.ECDSA
+
+		switch pub.Curve {
+		case elliptic.P224(), elliptic.P256():
+			hashFunc = crypto.SHA256
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+		case elliptic.P384():
+			hashFunc = crypto.SHA384
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+		case elliptic.P521():
+			hashFunc = crypto.SHA512
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+		default:
+			err = errors.New("x509: unknown elliptic curve")
+		}
+
+	default:
+		err = errors.New("x509: only RSA and ECDSA keys supported")
+	}
+
+	if err != nil {
+		return
+	}
+
+	if requestedSigAlgo == 0 {
+		return
+	}
+
+	found := false
+	for _, details := range signatureAlgorithmDetails {
+		if details.algo == requestedSigAlgo {
+			if details.pubKeyAlgo != pubType {
+				err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
+				return
+			}
+			sigAlgo.Algorithm, hashFunc = details.oid, details.hash
+			if hashFunc == 0 {
+				err = errors.New("x509: cannot sign with hash function requested")
+				return
+			}
+			found = true
+			break
+		}
+	}
+
+	if !found {
+		err = errors.New("x509: unknown SignatureAlgorithm")
+	}
+
+	return
+}
+
 // TODO(agl): this is taken from crypto/x509 and so should probably be exported
 // from crypto/x509 or crypto/x509/pkix.
 func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) x509.SignatureAlgorithm {
-	switch {
-	case oid.Equal(oidSignatureMD2WithRSA):
-		return x509.MD2WithRSA
-	case oid.Equal(oidSignatureMD5WithRSA):
-		return x509.MD5WithRSA
-	case oid.Equal(oidSignatureSHA1WithRSA):
-		return x509.SHA1WithRSA
-	case oid.Equal(oidSignatureSHA256WithRSA):
-		return x509.SHA256WithRSA
-	case oid.Equal(oidSignatureSHA384WithRSA):
-		return x509.SHA384WithRSA
-	case oid.Equal(oidSignatureSHA512WithRSA):
-		return x509.SHA512WithRSA
-	case oid.Equal(oidSignatureDSAWithSHA1):
-		return x509.DSAWithSHA1
-	case oid.Equal(oidSignatureDSAWithSHA256):
-		return x509.DSAWithSHA256
-	case oid.Equal(oidSignatureECDSAWithSHA1):
-		return x509.ECDSAWithSHA1
-	case oid.Equal(oidSignatureECDSAWithSHA256):
-		return x509.ECDSAWithSHA256
-	case oid.Equal(oidSignatureECDSAWithSHA384):
-		return x509.ECDSAWithSHA384
-	case oid.Equal(oidSignatureECDSAWithSHA512):
-		return x509.ECDSAWithSHA512
+	for _, details := range signatureAlgorithmDetails {
+		if oid.Equal(details.oid) {
+			return details.algo
+		}
 	}
 	return x509.UnknownSignatureAlgorithm
 }
 
+// TODO(rlb): This is not taken from crypto/x509, but it's of the same general form.
+func getHashAlgorithmFromOID(target asn1.ObjectIdentifier) crypto.Hash {
+	for hash, oid := range hashOIDs {
+		if oid.Equal(target) {
+			return hash
+		}
+	}
+	return crypto.Hash(0)
+}
+
 // This is the exposed reflection of the internal OCSP structures.
 
 const (
@@ -138,6 +241,14 @@
 	ServerFailed = iota
 )
 
+// Request represents an OCSP request. See RFC 2560.
+type Request struct {
+	HashAlgorithm  crypto.Hash
+	IssuerNameHash []byte
+	IssuerKeyHash  []byte
+	SerialNumber   *big.Int
+}
+
 // Response represents an OCSP response. See RFC 2560.
 type Response struct {
 	// Status is one of {Good, Revoked, Unknown, ServerFailed}
@@ -153,6 +264,18 @@
 	SignatureAlgorithm x509.SignatureAlgorithm
 }
 
+// These are pre-serialized error responses for the various non-success codes
+// defined by OCSP. The Unauthorized code in particular can be used by an OCSP
+// responder that supports only pre-signed responses as a response to requests
+// for certificates with unknown status. See RFC 5019.
+var (
+	MalformedRequestErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x01}
+	InternalErrorErrorResponse    = []byte{0x30, 0x03, 0x0A, 0x01, 0x02}
+	TryLaterErrorResponse         = []byte{0x30, 0x03, 0x0A, 0x01, 0x03}
+	SigRequredErrorResponse       = []byte{0x30, 0x03, 0x0A, 0x01, 0x05}
+	UnauthorizedErrorResponse     = []byte{0x30, 0x03, 0x0A, 0x01, 0x06}
+)
+
 // CheckSignatureFrom checks that the signature in resp is a valid signature
 // from issuer. This should only be used if resp.Certificate is nil. Otherwise,
 // the OCSP response contained an intermediate certificate that created the
@@ -169,6 +292,37 @@
 	return string(p)
 }
 
+// ParseRequest parses an OCSP request in DER form. It only supports
+// requests for a single certificate. Signed requests are not supported.
+// If a request includes a signature, it will result in a ParseError.
+func ParseRequest(bytes []byte) (*Request, error) {
+	var req ocspRequest
+	rest, err := asn1.Unmarshal(bytes, &req)
+	if err != nil {
+		return nil, err
+	}
+	if len(rest) > 0 {
+		return nil, ParseError("trailing data in OCSP request")
+	}
+
+	if len(req.TBSRequest.RequestList) == 0 {
+		return nil, ParseError("OCSP request contains no request body")
+	}
+	innerRequest := req.TBSRequest.RequestList[0]
+
+	hashFunc := getHashAlgorithmFromOID(innerRequest.Cert.HashAlgorithm.Algorithm)
+	if hashFunc == crypto.Hash(0) {
+		return nil, ParseError("OCSP request uses unknown hash function")
+	}
+
+	return &Request{
+		HashAlgorithm:  hashFunc,
+		IssuerNameHash: innerRequest.Cert.NameHash,
+		IssuerKeyHash:  innerRequest.Cert.IssuerKeyHash,
+		SerialNumber:   innerRequest.Cert.SerialNumber,
+	}, nil
+}
+
 // ParseResponse parses an OCSP response in DER form. It only supports
 // responses for a single certificate. If the response contains a certificate
 // then the signature over the response is checked. If issuer is not nil then
@@ -255,20 +409,6 @@
 	return ret, nil
 }
 
-// https://tools.ietf.org/html/rfc2560#section-4.1.1
-type ocspRequest struct {
-	TBSRequest tbsRequest
-}
-
-type tbsRequest struct {
-	Version     int `asn1:"explicit,tag:0,default:0"`
-	RequestList []request
-}
-
-type request struct {
-	Cert certID
-}
-
 // RequestOptions contains options for constructing OCSP requests.
 type RequestOptions struct {
 	// Hash contains the hash function that should be used when
@@ -293,16 +433,8 @@
 	// used. I took the following from
 	// http://msdn.microsoft.com/en-us/library/ff635603.aspx
 	var hashOID asn1.ObjectIdentifier
-	switch hashFunc {
-	case crypto.SHA1:
-		hashOID = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
-	case crypto.SHA256:
-		hashOID = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1})
-	case crypto.SHA384:
-		hashOID = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 2})
-	case crypto.SHA512:
-		hashOID = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 3})
-	default:
+	hashOID, ok := hashOIDs[hashFunc]
+	if !ok {
 		return nil, x509.ErrUnsupportedAlgorithm
 	}
 
@@ -345,3 +477,116 @@
 		},
 	})
 }
+
+// CreateResponse returns a DER-encoded OCSP response with the specified contents.
+// The fields in the response are populated as follows:
+//
+// The responder cert is used to populate the ResponderName field, and the certificate
+// itself is provided alongside the OCSP response signature.
+//
+// The issuer cert is used to puplate the IssuerNameHash and IssuerKeyHash fields.
+// (SHA-1 is used for the hash function; this is not configurable.)
+//
+// The template is used to populate the SerialNumber, RevocationStatus, RevokedAt,
+// RevocationReason, ThisUpdate, and NextUpdate fields.
+//
+// The ProducedAt date is automatically set to the current date, to the nearest minute.
+func CreateResponse(issuer, responderCert *x509.Certificate, template Response, priv crypto.Signer) ([]byte, error) {
+	var publicKeyInfo struct {
+		Algorithm pkix.AlgorithmIdentifier
+		PublicKey asn1.BitString
+	}
+	if _, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo); err != nil {
+		return nil, err
+	}
+
+	h := sha1.New()
+	h.Write(publicKeyInfo.PublicKey.RightAlign())
+	issuerKeyHash := h.Sum(nil)
+
+	h.Reset()
+	h.Write(issuer.RawSubject)
+	issuerNameHash := h.Sum(nil)
+
+	innerResponse := singleResponse{
+		CertID: certID{
+			HashAlgorithm: pkix.AlgorithmIdentifier{
+				Algorithm:  hashOIDs[crypto.SHA1],
+				Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */},
+			},
+			NameHash:      issuerNameHash,
+			IssuerKeyHash: issuerKeyHash,
+			SerialNumber:  template.SerialNumber,
+		},
+		ThisUpdate: template.ThisUpdate.UTC(),
+		NextUpdate: template.NextUpdate.UTC(),
+	}
+
+	switch template.Status {
+	case Good:
+		innerResponse.Good = true
+	case Unknown:
+		innerResponse.Unknown = true
+	case Revoked:
+		innerResponse.Revoked = revokedInfo{
+			RevocationTime: template.RevokedAt.UTC(),
+			Reason:         template.RevocationReason,
+		}
+	}
+
+	responderName := asn1.RawValue{
+		Class:      2, // context-specific
+		Tag:        1, // explicit tag
+		IsCompound: true,
+		Bytes:      responderCert.RawSubject,
+	}
+	tbsResponseData := responseData{
+		Version:          0,
+		RawResponderName: responderName,
+		ProducedAt:       time.Now().Truncate(time.Minute).UTC(),
+		Responses:        []singleResponse{innerResponse},
+	}
+
+	tbsResponseDataDER, err := asn1.Marshal(tbsResponseData)
+	if err != nil {
+		return nil, err
+	}
+
+	hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
+	if err != nil {
+		return nil, err
+	}
+
+	responseHash := hashFunc.New()
+	responseHash.Write(tbsResponseDataDER)
+	signature, err := priv.Sign(rand.Reader, responseHash.Sum(nil), hashFunc)
+	if err != nil {
+		return nil, err
+	}
+
+	response := basicResponse{
+		TBSResponseData:    tbsResponseData,
+		SignatureAlgorithm: signatureAlgorithm,
+		Signature: asn1.BitString{
+			Bytes:     signature,
+			BitLength: 8 * len(signature),
+		},
+	}
+	if template.Certificate != nil {
+		response.Certificates = []asn1.RawValue{
+			asn1.RawValue{FullBytes: template.Certificate.Raw},
+		}
+	}
+	responseDER, err := asn1.Marshal(response)
+	if err != nil {
+		return nil, err
+	}
+
+	return asn1.Marshal(responseASN1{
+		Status: ocspSuccess,
+		Response: responseBytes{
+			ResponseType: idPKIXOCSPBasic,
+			Response:     responseDER,
+		},
+	})
+}
diff --git a/go/src/golang.org/x/crypto/ocsp/ocsp_test.go b/go/src/golang.org/x/crypto/ocsp/ocsp_test.go
index fcdf6fe..5ea9eb2 100644
--- a/go/src/golang.org/x/crypto/ocsp/ocsp_test.go
+++ b/go/src/golang.org/x/crypto/ocsp/ocsp_test.go
@@ -6,7 +6,11 @@
 
 import (
 	"bytes"
+	"crypto"
+	"crypto/sha1"
 	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/asn1"
 	"encoding/hex"
 	"math/big"
 	"reflect"
@@ -89,9 +93,124 @@
 		t.Fatal(err)
 	}
 
-	expected, _ := hex.DecodeString(ocspRequestHex)
-	if !bytes.Equal(request, expected) {
-		t.Errorf("got %x, wanted %x", request, expected)
+	expectedBytes, _ := hex.DecodeString(ocspRequestHex)
+	if !bytes.Equal(request, expectedBytes) {
+		t.Errorf("request: got %x, wanted %x", request, expectedBytes)
+	}
+
+	decodedRequest, err := ParseRequest(expectedBytes)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if decodedRequest.HashAlgorithm != crypto.SHA1 {
+		t.Errorf("request.HashAlgorithm: got %v, want %v", decodedRequest.HashAlgorithm, crypto.SHA1)
+	}
+
+	var publicKeyInfo struct {
+		Algorithm pkix.AlgorithmIdentifier
+		PublicKey asn1.BitString
+	}
+	_, err = asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	h := sha1.New()
+	h.Write(publicKeyInfo.PublicKey.RightAlign())
+	issuerKeyHash := h.Sum(nil)
+
+	h.Reset()
+	h.Write(issuer.RawSubject)
+	issuerNameHash := h.Sum(nil)
+
+	if got := decodedRequest.IssuerKeyHash; !bytes.Equal(got, issuerKeyHash) {
+		t.Errorf("request.IssuerKeyHash: got %x, want %x", got, issuerKeyHash)
+	}
+
+	if got := decodedRequest.IssuerNameHash; !bytes.Equal(got, issuerNameHash) {
+		t.Errorf("request.IssuerKeyHash: got %x, want %x", got, issuerNameHash)
+	}
+
+	if got := decodedRequest.SerialNumber; got.Cmp(cert.SerialNumber) != 0 {
+		t.Errorf("request.SerialNumber: got %x, want %x", got, cert.SerialNumber)
+	}
+}
+
+func TestOCSPResponse(t *testing.T) {
+	leafCert, _ := hex.DecodeString(leafCertHex)
+	leaf, err := x509.ParseCertificate(leafCert)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	issuerCert, _ := hex.DecodeString(issuerCertHex)
+	issuer, err := x509.ParseCertificate(issuerCert)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	responderCert, _ := hex.DecodeString(responderCertHex)
+	responder, err := x509.ParseCertificate(responderCert)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	responderPrivateKeyDER, _ := hex.DecodeString(responderPrivateKeyHex)
+	responderPrivateKey, err := x509.ParsePKCS1PrivateKey(responderPrivateKeyDER)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	producedAt := time.Now().Truncate(time.Minute)
+	thisUpdate := time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC)
+	nextUpdate := time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC)
+	template := Response{
+		Status:           Revoked,
+		SerialNumber:     leaf.SerialNumber,
+		ThisUpdate:       thisUpdate,
+		NextUpdate:       nextUpdate,
+		RevokedAt:        thisUpdate,
+		RevocationReason: 1, // keyCompromise
+		Certificate:      responder,
+	}
+
+	responseBytes, err := CreateResponse(issuer, responder, template, responderPrivateKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	resp, err := ParseResponse(responseBytes, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !reflect.DeepEqual(resp.ThisUpdate, template.ThisUpdate) {
+		t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, template.ThisUpdate)
+	}
+
+	if !reflect.DeepEqual(resp.NextUpdate, template.NextUpdate) {
+		t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, template.NextUpdate)
+	}
+
+	if !reflect.DeepEqual(resp.RevokedAt, template.RevokedAt) {
+		t.Errorf("resp.RevokedAt: got %d, want %d", resp.RevokedAt, template.RevokedAt)
+	}
+
+	if !resp.ProducedAt.Equal(producedAt) {
+		t.Errorf("resp.ProducedAt: got %d, want %d", resp.ProducedAt, producedAt)
+	}
+
+	if resp.Status != template.Status {
+		t.Errorf("resp.Status: got %d, want %d", resp.Status, template.Status)
+	}
+
+	if resp.SerialNumber.Cmp(template.SerialNumber) != 0 {
+		t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, template.SerialNumber)
+	}
+
+	if resp.RevocationReason != template.RevocationReason {
+		t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, template.RevocationReason)
 	}
 }
 
@@ -214,9 +333,9 @@
 	"20a1a65c7f0b6427a224b3c98edd96b9b61f706099951188b0289555ad30a216fb774651" +
 	"5a35fca2e054dfa8"
 
-const ocspRequestHex = "30563054a003020100304d304b3049300906052b0e03021a05000414c0fe0278fc991888" +
-	"91b3f212e9c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210" +
-	"017f77deb3bcbb235d44ccc7dba62e72"
+const ocspRequestHex = "3051304f304d304b3049300906052b0e03021a05000414c0fe0278fc99188891b3f212e9" +
+	"c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210017f77deb3" +
+	"bcbb235d44ccc7dba62e72"
 
 const leafCertHex = "308203c830820331a0030201020210017f77deb3bcbb235d44ccc7dba62e72300d06092a" +
 	"864886f70d01010505003081ba311f301d060355040a1316566572695369676e20547275" +
@@ -272,3 +391,63 @@
 	"f5d93b0ab598fab378b91ef22b4c62d5fdb27a1ddf33fd73f9a5d82d8c2aead1fcb028b6" +
 	"e94948134b838a1b487b24f738de6f4154b8ab576b06dfc7a2d4a9f6f136628088f28b75" +
 	"d68071"
+
+// Key and certificate for the OCSP responder were not taken from the Thawte
+// responder, since CreateResponse requires that we have the private key.
+// Instead, they were generated randomly.
+const responderPrivateKeyHex = "308204a40201000282010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef" +
+	"1099f0f6616ec5265b56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df" +
+	"1701dc6ccfbcbec75a70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074f" +
+	"fde8a99d5b723350f0a112076614b12ef79c78991b119453445acf2416ab0046b540db14" +
+	"c9fc0f27b8989ad0f63aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa7" +
+	"7e7332971c7d285b6a04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f" +
+	"1290bafd97e655b1049a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb9" +
+	"6222b12ace31a77dcf920334dc94581b02030100010282010100bcf0b93d7238bda329a8" +
+	"72e7149f61bcb37c154330ccb3f42a85c9002c2e2bdea039d77d8581cd19bed94078794e" +
+	"56293d601547fc4bf6a2f9002fe5772b92b21b254403b403585e3130cc99ccf08f0ef81a" +
+	"575b38f597ba4660448b54f44bfbb97072b5a2bf043bfeca828cf7741d13698e3f38162b" +
+	"679faa646b82abd9a72c5c7d722c5fc577a76d2c2daac588accad18516d1bbad10b0dfa2" +
+	"05cfe246b59e28608a43942e1b71b0c80498075121de5b900d727c31c42c78cf1db5c0aa" +
+	"5b491e10ea4ed5c0962aaf2ae025dd81fa4ce490d9d6b4a4465411d8e542fc88617e5695" +
+	"1aa4fc8ea166f2b4d0eb89ef17f2b206bd5f1014bf8fe0e71fe62f2cccf102818100f2dc" +
+	"ddf878d553286daad68bac4070a82ffec3dc4666a2750f47879eec913f91836f1d976b60" +
+	"daf9356e078446dafab5bd2e489e5d64f8572ba24a4ba4f3729b5e106c4dd831cc2497a7" +
+	"e6c7507df05cb64aeb1bbc81c1e340d58b5964cf39cff84ea30c29ec5d3f005ee1362698" +
+	"07395037955955655292c3e85f6187fa1f9502818100f4a33c102630840705f8c778a47b" +
+	"87e8da31e68809af981ac5e5999cf1551685d761cdf0d6520361b99aebd5777a940fa64d" +
+	"327c09fa63746fbb3247ec73a86edf115f1fe5c83598db803881ade71c33c6e956118345" +
+	"497b98b5e07bb5be75971465ec78f2f9467e1b74956ca9d4c7c3e314e742a72d8b33889c" +
+	"6c093a466cef0281801d3df0d02124766dd0be98349b19eb36a508c4e679e793ba0a8bef" +
+	"4d786888c1e9947078b1ea28938716677b4ad8c5052af12eb73ac194915264a913709a0b" +
+	"7b9f98d4a18edd781a13d49899f91c20dbd8eb2e61d991ba19b5cdc08893f5cb9d39e5a6" +
+	"0629ea16d426244673b1b3ee72bd30e41fac8395acac40077403de5efd028180050731dd" +
+	"d71b1a2b96c8d538ba90bb6b62c8b1c74c03aae9a9f59d21a7a82b0d572ef06fa9c807bf" +
+	"c373d6b30d809c7871df96510c577421d9860c7383fda0919ece19996b3ca13562159193" +
+	"c0c246471e287f975e8e57034e5136aaf44254e2650def3d51292474c515b1588969112e" +
+	"0a85cc77073e9d64d2c2fc497844284b02818100d71d63eabf416cf677401ebf965f8314" +
+	"120b568a57dd3bd9116c629c40dc0c6948bab3a13cc544c31c7da40e76132ef5dd3f7534" +
+	"45a635930c74326ae3df0edd1bfb1523e3aa259873ac7cf1ac31151ec8f37b528c275622" +
+	"48f99b8bed59fd4da2576aa6ee20d93a684900bf907e80c66d6e2261ae15e55284b4ed9d" +
+	"6bdaa059"
+
+const responderCertHex = "308202e2308201caa003020102020101300d06092a864886f70d01010b05003019311730" +
+	"150603550403130e4f43535020526573706f6e646572301e170d31353031333031353530" +
+	"33335a170d3136303133303135353033335a3019311730150603550403130e4f43535020" +
+	"526573706f6e64657230820122300d06092a864886f70d01010105000382010f00308201" +
+	"0a0282010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef1099f0f6616e" +
+	"c5265b56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df1701dc6ccfbc" +
+	"bec75a70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074ffde8a99d5b72" +
+	"3350f0a112076614b12ef79c78991b119453445acf2416ab0046b540db14c9fc0f27b898" +
+	"9ad0f63aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa77e7332971c7d" +
+	"285b6a04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f1290bafd97e6" +
+	"55b1049a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb96222b12ace31" +
+	"a77dcf920334dc94581b0203010001a3353033300e0603551d0f0101ff04040302078030" +
+	"130603551d25040c300a06082b06010505070309300c0603551d130101ff04023000300d" +
+	"06092a864886f70d01010b05000382010100718012761b5063e18f0dc44644d8e6ab8612" +
+	"31c15fd5357805425d82aec1de85bf6d3e30fce205e3e3b8b795bbe52e40a439286d2288" +
+	"9064f4aeeb150359b9425f1da51b3a5c939018555d13ac42c565a0603786a919328f3267" +
+	"09dce52c22ad958ecb7873b9771d1148b1c4be2efe80ba868919fc9f68b6090c2f33c156" +
+	"d67156e42766a50b5d51e79637b7e58af74c2a951b1e642fa7741fec982cc937de37eff5" +
+	"9e2005d5939bfc031589ca143e6e8ab83f40ee08cc20a6b4a95a318352c28d18528dcaf9" +
+	"66705de17afa19d6e8ae91ddf33179d16ebb6ac2c69cae8373d408ebf8c55308be6c04d9" +
+	"3a25439a94299a65a709756c7a3e568be049d5c38839"
diff --git a/go/src/golang.org/x/crypto/openpgp/keys.go b/go/src/golang.org/x/crypto/openpgp/keys.go
index c4a6640..fe12cfa 100644
--- a/go/src/golang.org/x/crypto/openpgp/keys.go
+++ b/go/src/golang.org/x/crypto/openpgp/keys.go
@@ -6,11 +6,12 @@
 
 import (
 	"crypto/rsa"
+	"io"
+	"time"
+
 	"golang.org/x/crypto/openpgp/armor"
 	"golang.org/x/crypto/openpgp/errors"
 	"golang.org/x/crypto/openpgp/packet"
-	"io"
-	"time"
 )
 
 // PublicKeyType is the armor type for a PGP public key.
@@ -90,13 +91,16 @@
 func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
 	candidateSubkey := -1
 
+	// Iterate the keys to find the newest key
+	var maxTime time.Time
 	for i, subkey := range e.Subkeys {
 		if subkey.Sig.FlagsValid &&
 			subkey.Sig.FlagEncryptCommunications &&
 			subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
-			!subkey.Sig.KeyExpired(now) {
+			!subkey.Sig.KeyExpired(now) &&
+			(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
 			candidateSubkey = i
-			break
+			maxTime = subkey.Sig.CreationTime
 		}
 	}
 
diff --git a/go/src/golang.org/x/crypto/openpgp/keys_test.go b/go/src/golang.org/x/crypto/openpgp/keys_test.go
index e0625cb..d5e2056 100644
--- a/go/src/golang.org/x/crypto/openpgp/keys_test.go
+++ b/go/src/golang.org/x/crypto/openpgp/keys_test.go
@@ -1,9 +1,12 @@
 package openpgp
 
 import (
+	"bytes"
+	"strings"
 	"testing"
 	"time"
 
+	"golang.org/x/crypto/openpgp/errors"
 	"golang.org/x/crypto/openpgp/packet"
 )
 
@@ -13,15 +16,16 @@
 
 	const timeFormat = "2006-01-02"
 	time1, _ := time.Parse(timeFormat, "2013-07-01")
+
 	// The expiringKeyHex key is structured as:
 	//
-	// pub  1024R/5E237D8C  created: 2013-07-01  expires: 2013-07-31  usage: SC
-	// sub  1024R/1ABB25A0  created: 2013-07-01  expires: 2013-07-08  usage: E
-	// sub  1024R/96A672F5  created: 2013-07-01  expires: 2013-07-31  usage: E
+	// pub  1024R/5E237D8C  created: 2013-07-01                      expires: 2013-07-31  usage: SC
+	// sub  1024R/1ABB25A0  created: 2013-07-01 23:11:07 +0200 CEST  expires: 2013-07-08  usage: E
+	// sub  1024R/96A672F5  created: 2013-07-01 23:11:23 +0200 CEST  expires: 2013-07-31  usage: E
 	//
-	// So this should select the first, non-expired encryption key.
+	// So this should select the newest, non-expired encryption key.
 	key, _ := entity.encryptionKey(time1)
-	if id := key.PublicKey.KeyIdShortString(); id != "1ABB25A0" {
+	if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" {
 		t.Errorf("Expected key 1ABB25A0 at time %s, but got key %s", time1.Format(timeFormat), id)
 	}
 
@@ -40,6 +44,63 @@
 	}
 }
 
+func TestMissingCrossSignature(t *testing.T) {
+	// This public key has a signing subkey, but the subkey does not
+	// contain a cross-signature.
+	keys, err := ReadArmoredKeyRing(bytes.NewBufferString(missingCrossSignatureKey))
+	if len(keys) != 0 {
+		t.Errorf("Accepted key with missing cross signature")
+	}
+	if err == nil {
+		t.Fatal("Failed to detect error in keyring with missing cross signature")
+	}
+	structural, ok := err.(errors.StructuralError)
+	if !ok {
+		t.Fatalf("Unexpected class of error: %T. Wanted StructuralError", err)
+	}
+	const expectedMsg = "signing subkey is missing cross-signature"
+	if !strings.Contains(string(structural), expectedMsg) {
+		t.Fatalf("Unexpected error: %q. Expected it to contain %q", err, expectedMsg)
+	}
+}
+
+func TestInvalidCrossSignature(t *testing.T) {
+	// This public key has a signing subkey, and the subkey has an
+	// embedded cross-signature. However, the cross-signature does
+	// not correctly validate over the primary and subkey.
+	keys, err := ReadArmoredKeyRing(bytes.NewBufferString(invalidCrossSignatureKey))
+	if len(keys) != 0 {
+		t.Errorf("Accepted key with invalid cross signature")
+	}
+	if err == nil {
+		t.Fatal("Failed to detect error in keyring with an invalid cross signature")
+	}
+	structural, ok := err.(errors.StructuralError)
+	if !ok {
+		t.Fatalf("Unexpected class of error: %T. Wanted StructuralError", err)
+	}
+	const expectedMsg = "subkey signature invalid"
+	if !strings.Contains(string(structural), expectedMsg) {
+		t.Fatalf("Unexpected error: %q. Expected it to contain %q", err, expectedMsg)
+	}
+}
+
+func TestGoodCrossSignature(t *testing.T) {
+	// This public key has a signing subkey, and the subkey has an
+	// embedded cross-signature which correctly validates over the
+	// primary and subkey.
+	keys, err := ReadArmoredKeyRing(bytes.NewBufferString(goodCrossSignatureKey))
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(keys) != 1 {
+		t.Errorf("Failed to accept key with good cross signature, %d", len(keys))
+	}
+	if len(keys[0].Subkeys) != 1 {
+		t.Errorf("Failed to accept good subkey, %d", len(keys[0].Subkeys))
+	}
+}
+
 // TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission.
 func TestExternallyRevocableKey(t *testing.T) {
 	kring, _ := ReadKeyRing(readerFromHex(subkeyUsageHex))
@@ -214,3 +275,96 @@
 const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98"
 const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f"
 const revokedSubkeyHex = "988d04533121f6010400aefc803a3e4bb1a61c86e8a86d2726c6a43e0079e9f2713f1fa017e9854c83877f4aced8e331d675c67ea83ddab80aacbfa0b9040bb12d96f5a3d6be09455e2a76546cbd21677537db941cab710216b6d24ec277ee0bd65b910f416737ed120f6b93a9d3b306245c8cfd8394606fdb462e5cf43c551438d2864506c63367fc890011010001b41d416c696365203c616c69636540626d626172697374612e636f2e61753e88bb041301020025021b03060b090807030206150802090a0b0416020301021e01021780050253312798021901000a09104ef7e4beccde97f015a803ff5448437780f63263b0df8442a995e7f76c221351a51edd06f2063d8166cf3157aada4923dfc44aa0f2a6a4da5cf83b7fe722ba8ab416c976e77c6b5682e7f1069026673bd0de56ba06fd5d7a9f177607f277d9b55ff940a638c3e68525c67517e2b3d976899b93ca267f705b3e5efad7d61220e96b618a4497eab8d04403d23f8846041011020006050253312910000a09107b15a67f0b3ddc03d96e009f50b6365d86c4be5d5e9d0ea42d5e56f5794c617700a0ab274e19c2827780016d23417ce89e0a2c0d987d889c04100102000605025331cf7a000a0910a401d9f09a34f7c0ee970400aca292f213041c9f3b3fc49148cbda9d84afee6183c8dd6c5ff2600b29482db5fecd4303797be1ee6d544a20a858080fec43412061c9a71fae4039fd58013b4ae341273e6c66ad4c7cdd9e68245bedb260562e7b166f2461a1032f2b38c0e0e5715fb3d1656979e052b55ca827a76f872b78a9fdae64bc298170bfcebedc1271b41a416c696365203c616c696365407379646973702e6f722e61753e88b804130102002205025331278b021b03060b090807030206150802090a0b0416020301021e01021780000a09104ef7e4beccde97f06a7003fa03c3af68d272ebc1fa08aa72a03b02189c26496a2833d90450801c4e42c5b5f51ad96ce2d2c9cef4b7c02a6a2fcf1412d6a2d486098eb762f5010a201819c17fd2888aec8eda20c65a3b75744de7ee5cc8ac7bfc470cbe3cb982720405a27a3c6a8c229cfe36905f881b02ed5680f6a8f05866efb9d6c5844897e631deb949ca8846041011020006050253312910000a09107b15a67f0b3ddc0347bc009f7fa35db59147469eb6f2c5aaf6428accb138b22800a0caa2f5f0874bacc5909c652a57a31beda65eddd5889c04100102000605025331cf7a000a0910a401d9f09a34f7c0316403ff46f2a5c101256627f16384d34a38fb47a6c88ba60506843e532d91614339fccae5f884a5741e7582ffaf292ba38ee10a270a05f139bde3814b6a077e8cd2db0f105ebea2a83af70d385f13b507fac2ad93ff79d84950328bb86f3074745a8b7f9b64990fb142e2a12976e27e8d09a28dc5621f957ac49091116da410ac3cbde1b88d04533121f6010400cbd785b56905e4192e2fb62a720727d43c4fa487821203cf72138b884b78b701093243e1d8c92a0248a6c0203a5a88693da34af357499abacaf4b3309c640797d03093870a323b4b6f37865f6eaa2838148a67df4735d43a90ca87942554cdf1c4a751b1e75f9fd4ce4e97e278d6c1c7ed59d33441df7d084f3f02beb68896c70011010001889f0418010200090502533121f6021b0c000a09104ef7e4beccde97f0b98b03fc0a5ccf6a372995835a2f5da33b282a7d612c0ab2a97f59cf9fff73e9110981aac2858c41399afa29624a7fd8a0add11654e3d882c0fd199e161bdad65e5e2548f7b68a437ea64293db1246e3011cbb94dc1bcdeaf0f2539bd88ff16d95547144d97cead6a8c5927660a91e6db0d16eb36b7b49a3525b54d1644e65599b032b7eb901a204533127a0110400bd3edaa09eff9809c4edc2c2a0ebe52e53c50a19c1e49ab78e6167bf61473bb08f2050d78a5cbbc6ed66aff7b42cd503f16b4a0b99fa1609681fca9b7ce2bbb1a5b3864d6cdda4d7ef7849d156d534dea30fb0efb9e4cf8959a2b2ce623905882d5430b995a15c3b9fe92906086788b891002924f94abe139b42cbbfaaabe42f00a0b65dc1a1ad27d798adbcb5b5ad02d2688c89477b03ff4eebb6f7b15a73b96a96bed201c0e5e4ea27e4c6e2dd1005b94d4b90137a5b1cf5e01c6226c070c4cc999938101578877ee76d296b9aab8246d57049caacf489e80a3f40589cade790a020b1ac146d6f7a6241184b8c7fcde680eae3188f5dcbe846d7f7bdad34f6fcfca08413e19c1d5df83fc7c7c627d493492e009c2f52a80400a2fe82de87136fd2e8845888c4431b032ba29d9a29a804277e31002a8201fb8591a3e55c7a0d0881496caf8b9fb07544a5a4879291d0dc026a0ea9e5bd88eb4aa4947bbd694b25012e208a250d65ddc6f1eea59d3aed3b4ec15fcab85e2afaa23a40ab1ef9ce3e11e1bc1c34a0e758e7aa64deb8739276df0af7d4121f834a9b88e70418010200090502533127a0021b02005209104ef7e4beccde97f047200419110200060502533127a0000a0910dbce4ee19529437fe045009c0b32f5ead48ee8a7e98fac0dea3d3e6c0e2c552500a0ad71fadc5007cfaf842d9b7db3335a8cdad15d3d1a6404009b08e2c68fe8f3b45c1bb72a4b3278cdf3012aa0f229883ad74aa1f6000bb90b18301b2f85372ca5d6b9bf478d235b733b1b197d19ccca48e9daf8e890cb64546b4ce1b178faccfff07003c172a2d4f5ebaba9f57153955f3f61a9b80a4f5cb959908f8b211b03b7026a8a82fc612bfedd3794969bcf458c4ce92be215a1176ab88d045331d144010400a5063000c5aaf34953c1aa3bfc95045b3aab9882b9a8027fecfe2142dc6b47ba8aca667399990244d513dd0504716908c17d92c65e74219e004f7b83fc125e575dd58efec3ab6dd22e3580106998523dea42ec75bf9aa111734c82df54630bebdff20fe981cfc36c76f865eb1c2fb62c9e85bc3a6e5015a361a2eb1c8431578d0011010001889f04280102000905025331d433021d03000a09104ef7e4beccde97f02e5503ff5e0630d1b65291f4882b6d40a29da4616bb5088717d469fbcc3648b8276de04a04988b1f1b9f3e18f52265c1f8b6c85861691c1a6b8a3a25a1809a0b32ad330aec5667cb4262f4450649184e8113849b05e5ad06a316ea80c001e8e71838190339a6e48bbde30647bcf245134b9a97fa875c1d83a9862cae87ffd7e2c4ce3a1b89013d04180102000905025331d144021b0200a809104ef7e4beccde97f09d2004190102000605025331d144000a0910677815e371c2fd23522203fe22ab62b8e7a151383cea3edd3a12995693911426f8ccf125e1f6426388c0010f88d9ca7da2224aee8d1c12135998640c5e1813d55a93df472faae75bef858457248db41b4505827590aeccf6f9eb646da7f980655dd3050c6897feddddaca90676dee856d66db8923477d251712bb9b3186b4d0114daf7d6b59272b53218dd1da94a03ff64006fcbe71211e5daecd9961fba66cdb6de3f914882c58ba5beddeba7dcb950c1156d7fba18c19ea880dccc800eae335deec34e3b84ac75ffa24864f782f87815cda1c0f634b3dd2fa67cea30811d21723d21d9551fa12ccbcfa62b6d3a15d01307b99925707992556d50065505b090aadb8579083a20fe65bd2a270da9b011"
+const missingCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Charset: UTF-8
+
+mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY
+ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG
+zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54
+QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ
+QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo
+9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu
+Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/
+dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R
+JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL
+ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew
+RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW
+/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu
+yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAJcXQeP+NmuciE99YcJoffxv
+2gVLU4ZXBNHEaP0mgaJ1+tmMD089vUQAcyGRvw8jfsNsVZQIOAuRxY94aHQhIRHR
+bUzBN28ofo/AJJtfx62C15xt6fDKRV6HXYqAiygrHIpEoRLyiN69iScUsjIJeyFL
+C8wa72e8pSL6dkHoaV1N9ZH/xmrJ+k0vsgkQaAh9CzYufncDxcwkoP+aOlGtX1gP
+WwWoIbz0JwLEMPHBWvDDXQcQPQTYQyj+LGC9U6f9VZHN25E94subM1MjuT9OhN9Y
+MLfWaaIc5WyhLFyQKW2Upofn9wSFi8ubyBnv640Dfd0rVmaWv7LNTZpoZ/GbJAMA
+EQEAAYkBHwQYAQIACQUCU5ygeQIbAgAKCRDt1A0FCB6SP0zCB/sEzaVR38vpx+OQ
+MMynCBJrakiqDmUZv9xtplY7zsHSQjpd6xGflbU2n+iX99Q+nav0ETQZifNUEd4N
+1ljDGQejcTyKD6Pkg6wBL3x9/RJye7Zszazm4+toJXZ8xJ3800+BtaPoI39akYJm
++ijzbskvN0v/j5GOFJwQO0pPRAFtdHqRs9Kf4YanxhedB4dIUblzlIJuKsxFit6N
+lgGRblagG3Vv2eBszbxzPbJjHCgVLR3RmrVezKOsZjr/2i7X+xLWIR0uD3IN1qOW
+CXQxLBizEEmSNVNxsp7KPGTLnqO3bPtqFirxS9PJLIMPTPLNBY7ZYuPNTMqVIUWF
+4artDmrG
+=7FfJ
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const invalidCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY
+ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG
+zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54
+QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ
+QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo
+9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu
+Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/
+dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R
+JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL
+ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew
+RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW
+/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu
+yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAIINDqlj7X6jYKc6DjwrOkjQ
+UIRWbQQar0LwmNilehmt70g5DCL1SYm9q4LcgJJ2Nhxj0/5qqsYib50OSWMcKeEe
+iRXpXzv1ObpcQtI5ithp0gR53YPXBib80t3bUzomQ5UyZqAAHzMp3BKC54/vUrSK
+FeRaxDzNLrCeyI00+LHNUtwghAqHvdNcsIf8VRumK8oTm3RmDh0TyjASWYbrt9c8
+R1Um3zuoACOVy+mEIgIzsfHq0u7dwYwJB5+KeM7ZLx+HGIYdUYzHuUE1sLwVoELh
++SHIGHI1HDicOjzqgajShuIjj5hZTyQySVprrsLKiXS6NEwHAP20+XjayJ/R3tEA
+EQEAAYkCPgQYAQIBKAUCU5ygeQIbAsBdIAQZAQIABgUCU5ygeQAKCRCpVlnFZmhO
+52RJB/9uD1MSa0wjY6tHOIgquZcP3bHBvHmrHNMw9HR2wRCMO91ZkhrpdS3ZHtgb
+u3/55etj0FdvDo1tb8P8FGSVtO5Vcwf5APM8sbbqoi8L951Q3i7qt847lfhu6sMl
+w0LWFvPTOLHrliZHItPRjOltS1WAWfr2jUYhsU9ytaDAJmvf9DujxEOsN5G1YJep
+54JCKVCkM/y585Zcnn+yxk/XwqoNQ0/iJUT9qRrZWvoeasxhl1PQcwihCwss44A+
+YXaAt3hbk+6LEQuZoYS73yR3WHj+42tfm7YxRGeubXfgCEz/brETEWXMh4pe0vCL
+bfWrmfSPq2rDegYcAybxRQz0lF8PAAoJEO3UDQUIHpI/exkH/0vQfdHA8g/N4T6E
+i6b1CUVBAkvtdJpCATZjWPhXmShOw62gkDw306vHPilL4SCvEEi4KzG72zkp6VsB
+DSRcpxCwT4mHue+duiy53/aRMtSJ+vDfiV1Vhq+3sWAck/yUtfDU9/u4eFaiNok1
+8/Gd7reyuZt5CiJnpdPpjCwelK21l2w7sHAnJF55ITXdOxI8oG3BRKufz0z5lyDY
+s2tXYmhhQIggdgelN8LbcMhWs/PBbtUr6uZlNJG2lW1yscD4aI529VjwJlCeo745
+U7pO4eF05VViUJ2mmfoivL3tkhoTUWhx8xs8xCUcCg8DoEoSIhxtOmoTPR22Z9BL
+6LCg2mg=
+=Dhm4
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const goodCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mI0EVUqeVwEEAMufHRrMPWK3gyvi0O0tABCs/oON9zV9KDZlr1a1M91ShCSFwCPo
+7r80PxdWVWcj0V5h50/CJYtpN3eE/mUIgW2z1uDYQF1OzrQ8ubrksfsJvpAhENom
+lTQEppv9mV8qhcM278teb7TX0pgrUHLYF5CfPdp1L957JLLXoQR/lwLVABEBAAG0
+E2dvb2Qtc2lnbmluZy1zdWJrZXmIuAQTAQIAIgUCVUqeVwIbAwYLCQgHAwIGFQgC
+CQoLBBYCAwECHgECF4AACgkQNRjL95IRWP69XQQAlH6+eyXJN4DZTLX78KGjHrsw
+6FCvxxClEPtPUjcJy/1KCRQmtLAt9PbbA78dvgzjDeZMZqRAwdjyJhjyg/fkU2OH
+7wq4ktjUu+dLcOBb+BFMEY+YjKZhf6EJuVfxoTVr5f82XNPbYHfTho9/OABKH6kv
+X70PaKZhbwnwij8Nts65AaIEVUqftREEAJ3WxZfqAX0bTDbQPf2CMT2IVMGDfhK7
+GyubOZgDFFjwUJQvHNvsrbeGLZ0xOBumLINyPO1amIfTgJNm1iiWFWfmnHReGcDl
+y5mpYG60Mb79Whdcer7CMm3AqYh/dW4g6IB02NwZMKoUHo3PXmFLxMKXnWyJ0clw
+R0LI/Qn509yXAKDh1SO20rqrBM+EAP2c5bfI98kyNwQAi3buu94qo3RR1ZbvfxgW
+CKXDVm6N99jdZGNK7FbRifXqzJJDLcXZKLnstnC4Sd3uyfyf1uFhmDLIQRryn5m+
+LBYHfDBPN3kdm7bsZDDq9GbTHiFZUfm/tChVKXWxkhpAmHhU/tH6GGzNSMXuIWSO
+aOz3Rqq0ED4NXyNKjdF9MiwD/i83S0ZBc0LmJYt4Z10jtH2B6tYdqnAK29uQaadx
+yZCX2scE09UIm32/w7pV77CKr1Cp/4OzAXS1tmFzQ+bX7DR+Gl8t4wxr57VeEMvl
+BGw4Vjh3X8//m3xynxycQU18Q1zJ6PkiMyPw2owZ/nss3hpSRKFJsxMLhW3fKmKr
+Ey2KiOcEGAECAAkFAlVKn7UCGwIAUgkQNRjL95IRWP5HIAQZEQIABgUCVUqftQAK
+CRD98VjDN10SqkWrAKDTpEY8D8HC02E/KVC5YUI01B30wgCgurpILm20kXEDCeHp
+C5pygfXw1DJrhAP+NyPJ4um/bU1I+rXaHHJYroYJs8YSweiNcwiHDQn0Engh/mVZ
+SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/
+MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70=
+=vtbN
+-----END PGP PUBLIC KEY BLOCK-----`
diff --git a/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key.go b/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key.go
index b43522c..266840d 100644
--- a/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key.go
+++ b/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key.go
@@ -7,11 +7,12 @@
 import (
 	"crypto/rsa"
 	"encoding/binary"
-	"golang.org/x/crypto/openpgp/elgamal"
-	"golang.org/x/crypto/openpgp/errors"
 	"io"
 	"math/big"
 	"strconv"
+
+	"golang.org/x/crypto/openpgp/elgamal"
+	"golang.org/x/crypto/openpgp/errors"
 )
 
 const encryptedKeyVersion = 3
@@ -24,7 +25,7 @@
 	CipherFunc CipherFunction // only valid after a successful Decrypt
 	Key        []byte         // only valid after a successful Decrypt
 
-	encryptedMPI1, encryptedMPI2 []byte
+	encryptedMPI1, encryptedMPI2 parsedMPI
 }
 
 func (e *EncryptedKey) parse(r io.Reader) (err error) {
@@ -40,13 +41,13 @@
 	e.Algo = PublicKeyAlgorithm(buf[9])
 	switch e.Algo {
 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
-		e.encryptedMPI1, _, err = readMPI(r)
+		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
 	case PubKeyAlgoElGamal:
-		e.encryptedMPI1, _, err = readMPI(r)
+		e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
 		if err != nil {
 			return
 		}
-		e.encryptedMPI2, _, err = readMPI(r)
+		e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r)
 	}
 	_, err = consumeAll(r)
 	return
@@ -71,10 +72,10 @@
 	// padding oracle attacks.
 	switch priv.PubKeyAlgo {
 	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
-		b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1)
+		b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes)
 	case PubKeyAlgoElGamal:
-		c1 := new(big.Int).SetBytes(e.encryptedMPI1)
-		c2 := new(big.Int).SetBytes(e.encryptedMPI2)
+		c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
+		c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
 		b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
 	default:
 		err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
@@ -95,6 +96,36 @@
 	return nil
 }
 
+// Serialize writes the encrypted key packet, e, to w.
+func (e *EncryptedKey) Serialize(w io.Writer) error {
+	var mpiLen int
+	switch e.Algo {
+	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+		mpiLen = 2 + len(e.encryptedMPI1.bytes)
+	case PubKeyAlgoElGamal:
+		mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes)
+	default:
+		return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
+	}
+
+	serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen)
+
+	w.Write([]byte{encryptedKeyVersion})
+	binary.Write(w, binary.BigEndian, e.KeyId)
+	w.Write([]byte{byte(e.Algo)})
+
+	switch e.Algo {
+	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+		writeMPIs(w, e.encryptedMPI1)
+	case PubKeyAlgoElGamal:
+		writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2)
+	default:
+		panic("internal error")
+	}
+
+	return nil
+}
+
 // SerializeEncryptedKey serializes an encrypted key packet to w that contains
 // key, encrypted to pub.
 // If config is nil, sensible defaults will be used.
diff --git a/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go b/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go
index 0a8dcc6..fee14cf 100644
--- a/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go
+++ b/go/src/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go
@@ -7,6 +7,7 @@
 import (
 	"bytes"
 	"crypto/rsa"
+	"encoding/hex"
 	"fmt"
 	"math/big"
 	"testing"
@@ -123,3 +124,23 @@
 		t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
 	}
 }
+
+func TestSerializingEncryptedKey(t *testing.T) {
+	const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+
+	p, err := Read(readerFromHex(encryptedKeyHex))
+	if err != nil {
+		t.Fatalf("error from Read: %s", err)
+	}
+	ek, ok := p.(*EncryptedKey)
+	if !ok {
+		t.Fatalf("didn't parse an EncryptedKey, got %#v", p)
+	}
+
+	var buf bytes.Buffer
+	ek.Serialize(&buf)
+
+	if bufHex := hex.EncodeToString(buf.Bytes()); bufHex != encryptedKeyHex {
+		t.Fatalf("serialization of encrypted key differed from original. Original was %s, but reserialized as %s", encryptedKeyHex, bufHex)
+	}
+}
diff --git a/go/src/golang.org/x/crypto/openpgp/packet/packet.go b/go/src/golang.org/x/crypto/openpgp/packet/packet.go
index 2e6b349..e2bde11 100644
--- a/go/src/golang.org/x/crypto/openpgp/packet/packet.go
+++ b/go/src/golang.org/x/crypto/openpgp/packet/packet.go
@@ -385,16 +385,17 @@
 type SignatureType uint8
 
 const (
-	SigTypeBinary           SignatureType = 0
-	SigTypeText                           = 1
-	SigTypeGenericCert                    = 0x10
-	SigTypePersonaCert                    = 0x11
-	SigTypeCasualCert                     = 0x12
-	SigTypePositiveCert                   = 0x13
-	SigTypeSubkeyBinding                  = 0x18
-	SigTypeDirectSignature                = 0x1F
-	SigTypeKeyRevocation                  = 0x20
-	SigTypeSubkeyRevocation               = 0x28
+	SigTypeBinary            SignatureType = 0
+	SigTypeText                            = 1
+	SigTypeGenericCert                     = 0x10
+	SigTypePersonaCert                     = 0x11
+	SigTypeCasualCert                      = 0x12
+	SigTypePositiveCert                    = 0x13
+	SigTypeSubkeyBinding                   = 0x18
+	SigTypePrimaryKeyBinding               = 0x19
+	SigTypeDirectSignature                 = 0x1F
+	SigTypeKeyRevocation                   = 0x20
+	SigTypeSubkeyRevocation                = 0x28
 )
 
 // PublicKeyAlgorithm represents the different public key system specified for
@@ -427,7 +428,7 @@
 // sign a message.
 func (pka PublicKeyAlgorithm) CanSign() bool {
 	switch pka {
-	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
+	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA:
 		return true
 	}
 	return false
diff --git a/go/src/golang.org/x/crypto/openpgp/packet/public_key.go b/go/src/golang.org/x/crypto/openpgp/packet/public_key.go
index 26bd9cc..c3fb188 100644
--- a/go/src/golang.org/x/crypto/openpgp/packet/public_key.go
+++ b/go/src/golang.org/x/crypto/openpgp/packet/public_key.go
@@ -16,13 +16,14 @@
 	_ "crypto/sha512"
 	"encoding/binary"
 	"fmt"
-	"golang.org/x/crypto/openpgp/elgamal"
-	"golang.org/x/crypto/openpgp/errors"
 	"hash"
 	"io"
 	"math/big"
 	"strconv"
 	"time"
+
+	"golang.org/x/crypto/openpgp/elgamal"
+	"golang.org/x/crypto/openpgp/errors"
 )
 
 var (
@@ -192,7 +193,7 @@
 	return pk
 }
 
-// NewDSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
+// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey.
 func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey {
 	pk := &PublicKey{
 		CreationTime: creationTime,
@@ -564,12 +565,33 @@
 
 // VerifyKeySignature returns nil iff sig is a valid signature, made by this
 // public key, of signed.
-func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err error) {
+func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error {
 	h, err := keySignatureHash(pk, signed, sig.Hash)
 	if err != nil {
 		return err
 	}
-	return pk.VerifySignature(h, sig)
+	if err = pk.VerifySignature(h, sig); err != nil {
+		return err
+	}
+
+	if sig.FlagSign {
+		// Signing subkeys must be cross-signed. See
+		// https://www.gnupg.org/faq/subkey-cross-certify.html.
+		if sig.EmbeddedSignature == nil {
+			return errors.StructuralError("signing subkey is missing cross-signature")
+		}
+		// Verify the cross-signature. This is calculated over the same
+		// data as the main signature, so we cannot just recursively
+		// call signed.VerifyKeySignature(...)
+		if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil {
+			return errors.StructuralError("error while hashing for cross-signature: " + err.Error())
+		}
+		if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil {
+			return errors.StructuralError("error while verifying cross-signature: " + err.Error())
+		}
+	}
+
+	return nil
 }
 
 func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
diff --git a/go/src/golang.org/x/crypto/openpgp/packet/reader.go b/go/src/golang.org/x/crypto/openpgp/packet/reader.go
index 753bf8f..34bc7c6 100644
--- a/go/src/golang.org/x/crypto/openpgp/packet/reader.go
+++ b/go/src/golang.org/x/crypto/openpgp/packet/reader.go
@@ -16,6 +16,14 @@
 	readers []io.Reader
 }
 
+// New io.Readers are pushed when a compressed or encrypted packet is processed
+// and recursively treated as a new source of packets. However, a carefully
+// crafted packet can trigger an infinite recursive sequence of packets. See
+// http://mumble.net/~campbell/misc/pgp-quine
+// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402
+// This constant limits the number of recursive packets that may be pushed.
+const maxReaders = 32
+
 // Next returns the most recently unread Packet, or reads another packet from
 // the top-most io.Reader. Unknown packet types are skipped.
 func (r *Reader) Next() (p Packet, err error) {
@@ -44,9 +52,15 @@
 
 // Push causes the Reader to start reading from a new io.Reader. When an EOF
 // error is seen from the new io.Reader, it is popped and the Reader continues
-// to read from the next most recent io.Reader.
-func (r *Reader) Push(reader io.Reader) {
+// to read from the next most recent io.Reader. Push returns a StructuralError
+// if pushing the reader would exceed the maximum recursion level, otherwise it
+// returns nil.
+func (r *Reader) Push(reader io.Reader) (err error) {
+	if len(r.readers) >= maxReaders {
+		return errors.StructuralError("too many layers of packets")
+	}
 	r.readers = append(r.readers, reader)
+	return nil
 }
 
 // Unread causes the given Packet to be returned from the next call to Next.
diff --git a/go/src/golang.org/x/crypto/openpgp/packet/signature.go b/go/src/golang.org/x/crypto/openpgp/packet/signature.go
index 79cf993..1f29d3d 100644
--- a/go/src/golang.org/x/crypto/openpgp/packet/signature.go
+++ b/go/src/golang.org/x/crypto/openpgp/packet/signature.go
@@ -5,16 +5,18 @@
 package packet
 
 import (
+	"bytes"
 	"crypto"
 	"crypto/dsa"
 	"crypto/rsa"
 	"encoding/binary"
-	"golang.org/x/crypto/openpgp/errors"
-	"golang.org/x/crypto/openpgp/s2k"
 	"hash"
 	"io"
 	"strconv"
 	"time"
+
+	"golang.org/x/crypto/openpgp/errors"
+	"golang.org/x/crypto/openpgp/s2k"
 )
 
 const (
@@ -63,6 +65,15 @@
 	RevocationReason     *uint8
 	RevocationReasonText string
 
+	// MDC is set if this signature has a feature packet that indicates
+	// support for MDC subpackets.
+	MDC bool
+
+	// EmbeddedSignature, if non-nil, is a signature of the parent key, by
+	// this key. This prevents an attacker from claiming another's signing
+	// subkey as their own.
+	EmbeddedSignature *Signature
+
 	outSubpackets []outputSubpacket
 }
 
@@ -190,6 +201,8 @@
 	primaryUserIdSubpacket       signatureSubpacketType = 25
 	keyFlagsSubpacket            signatureSubpacketType = 27
 	reasonForRevocationSubpacket signatureSubpacketType = 29
+	featuresSubpacket            signatureSubpacketType = 30
+	embeddedSignatureSubpacket   signatureSubpacketType = 32
 )
 
 // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
@@ -343,7 +356,30 @@
 		sig.RevocationReason = new(uint8)
 		*sig.RevocationReason = subpacket[0]
 		sig.RevocationReasonText = string(subpacket[1:])
-
+	case featuresSubpacket:
+		// Features subpacket, section 5.2.3.24 specifies a very general
+		// mechanism for OpenPGP implementations to signal support for new
+		// features. In practice, the subpacket is used exclusively to
+		// indicate support for MDC-protected encryption.
+		sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1
+	case embeddedSignatureSubpacket:
+		// Only usage is in signatures that cross-certify
+		// signing subkeys. section 5.2.3.26 describes the
+		// format, with its usage described in section 11.1
+		if sig.EmbeddedSignature != nil {
+			err = errors.StructuralError("Cannot have multiple embedded signatures")
+			return
+		}
+		sig.EmbeddedSignature = new(Signature)
+		// Embedded signatures are required to be v4 signatures see
+		// section 12.1. However, we only parse v4 signatures in this
+		// file anyway.
+		if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil {
+			return nil, err
+		}
+		if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding {
+			return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType)))
+		}
 	default:
 		if isCritical {
 			err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
diff --git a/go/src/golang.org/x/crypto/openpgp/read.go b/go/src/golang.org/x/crypto/openpgp/read.go
index c50a509..dff65a8 100644
--- a/go/src/golang.org/x/crypto/openpgp/read.go
+++ b/go/src/golang.org/x/crypto/openpgp/read.go
@@ -211,7 +211,9 @@
 	}
 
 	md.decrypted = decrypted
-	packets.Push(decrypted)
+	if err := packets.Push(decrypted); err != nil {
+		return nil, err
+	}
 	return readSignedMessage(packets, md, keyring)
 }
 
@@ -235,7 +237,9 @@
 		}
 		switch p := p.(type) {
 		case *packet.Compressed:
-			packets.Push(p.Body)
+			if err := packets.Push(p.Body); err != nil {
+				return nil, err
+			}
 		case *packet.OnePassSignature:
 			if !p.IsLast {
 				return nil, errors.UnsupportedError("nested signatures")
diff --git a/go/src/golang.org/x/crypto/openpgp/read_test.go b/go/src/golang.org/x/crypto/openpgp/read_test.go
index c2720ae..03bf5d8 100644
--- a/go/src/golang.org/x/crypto/openpgp/read_test.go
+++ b/go/src/golang.org/x/crypto/openpgp/read_test.go
@@ -135,6 +135,25 @@
 	checkSignedMessage(t, signedTextMessageHex, signedTextInput)
 }
 
+// The reader should detect "compressed quines", which are compressed
+// packets that expand into themselves and cause an infinite recursive
+// parsing loop.
+// The packet in this test case comes from Taylor R. Campbell at
+// http://mumble.net/~campbell/misc/pgp-quine/
+func TestCampbellQuine(t *testing.T) {
+	md, err := ReadMessage(readerFromHex(campbellQuine), nil, nil, nil)
+	if md != nil {
+		t.Errorf("Reading a compressed quine should not return any data: %#v", md)
+	}
+	structural, ok := err.(errors.StructuralError)
+	if !ok {
+		t.Fatalf("Unexpected class of error: %T", err)
+	}
+	if !strings.Contains(string(structural), "too many layers of packets") {
+		t.Fatalf("Unexpected error: %s", err)
+	}
+}
+
 var signedEncryptedMessageTests = []struct {
 	keyRingHex       string
 	messageHex       string
@@ -332,6 +351,16 @@
 	}
 }
 
+func TestReadingArmoredPublicKey(t *testing.T) {
+	el, err := ReadArmoredKeyRing(bytes.NewBufferString(e2ePublicKey))
+	if err != nil {
+		t.Error(err)
+	}
+	if len(el) != 1 {
+		t.Errorf("didn't get a valid entity")
+	}
+}
+
 func TestNoArmoredData(t *testing.T) {
 	_, err := ReadArmoredKeyRing(bytes.NewBufferString("foo"))
 	if _, ok := err.(errors.InvalidArgumentError); !ok {
@@ -409,8 +438,26 @@
 =zNCn
 -----END PGP PRIVATE KEY BLOCK-----`
 
+const e2ePublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Charset: UTF-8
+
+xv8AAABSBAAAAAATCCqGSM49AwEHAgME1LRoXSpOxtHXDUdmuvzchyg6005qIBJ4
+sfaSxX7QgH9RV2ONUhC+WiayCNADq+UMzuR/vunSr4aQffXvuGnR383/AAAAFDxk
+Z2lsQHlhaG9vLWluYy5jb20+wv8AAACGBBATCAA4/wAAAAWCVGvAG/8AAAACiwn/
+AAAACZC2VkQCOjdvYf8AAAAFlQgJCgv/AAAAA5YBAv8AAAACngEAAE1BAP0X8veD
+24IjmI5/C6ZAfVNXxgZZFhTAACFX75jUA3oD6AEAzoSwKf1aqH6oq62qhCN/pekX
++WAsVMBhNwzLpqtCRjLO/wAAAFYEAAAAABIIKoZIzj0DAQcCAwT50ain7vXiIRv8
+B1DO3x3cE/aattZ5sHNixJzRCXi2vQIA5QmOxZ6b5jjUekNbdHG3SZi1a2Ak5mfX
+fRxC/5VGAwEIB8L/AAAAZQQYEwgAGP8AAAAFglRrwBz/AAAACZC2VkQCOjdvYQAA
+FJAA9isX3xtGyMLYwp2F3nXm7QEdY5bq5VUcD/RJlj792VwA/1wH0pCzVLl4Q9F9
+ex7En5r7rHR5xwX82Msc+Rq9dSyO
+=7MrZ
+-----END PGP PUBLIC KEY BLOCK-----`
+
 const dsaKeyWithSHA512 = `9901a2044f04b07f110400db244efecc7316553ee08d179972aab87bb1214de7692593fcf5b6feb1c80fba268722dd464748539b85b81d574cd2d7ad0ca2444de4d849b8756bad7768c486c83a824f9bba4af773d11742bdfb4ac3b89ef8cc9452d4aad31a37e4b630d33927bff68e879284a1672659b8b298222fc68f370f3e24dccacc4a862442b9438b00a0ea444a24088dc23e26df7daf8f43cba3bffc4fe703fe3d6cd7fdca199d54ed8ae501c30e3ec7871ea9cdd4cf63cfe6fc82281d70a5b8bb493f922cd99fba5f088935596af087c8d818d5ec4d0b9afa7f070b3d7c1dd32a84fca08d8280b4890c8da1dde334de8e3cad8450eed2a4a4fcc2db7b8e5528b869a74a7f0189e11ef097ef1253582348de072bb07a9fa8ab838e993cef0ee203ff49298723e2d1f549b00559f886cd417a41692ce58d0ac1307dc71d85a8af21b0cf6eaa14baf2922d3a70389bedf17cc514ba0febbd107675a372fe84b90162a9e88b14d4b1c6be855b96b33fb198c46f058568817780435b6936167ebb3724b680f32bf27382ada2e37a879b3d9de2abe0c3f399350afd1ad438883f4791e2e3b4184453412068617368207472756e636174696f6e207465737488620413110a002205024f04b07f021b03060b090807030206150802090a0b0416020301021e01021780000a0910ef20e0cefca131581318009e2bf3bf047a44d75a9bacd00161ee04d435522397009a03a60d51bd8a568c6c021c8d7cf1be8d990d6417b0020003`
 
 const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6acc0b21f32ffff01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101`
 
 const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000`
diff --git a/go/src/golang.org/x/crypto/openpgp/write.go b/go/src/golang.org/x/crypto/openpgp/write.go
index e471174..15aaa1a 100644
--- a/go/src/golang.org/x/crypto/openpgp/write.go
+++ b/go/src/golang.org/x/crypto/openpgp/write.go
@@ -6,14 +6,15 @@
 
 import (
 	"crypto"
-	"golang.org/x/crypto/openpgp/armor"
-	"golang.org/x/crypto/openpgp/errors"
-	"golang.org/x/crypto/openpgp/packet"
-	"golang.org/x/crypto/openpgp/s2k"
 	"hash"
 	"io"
 	"strconv"
 	"time"
+
+	"golang.org/x/crypto/openpgp/armor"
+	"golang.org/x/crypto/openpgp/errors"
+	"golang.org/x/crypto/openpgp/packet"
+	"golang.org/x/crypto/openpgp/s2k"
 )
 
 // DetachSign signs message with the private key from signer (which must
@@ -176,6 +177,9 @@
 			return nil, errors.InvalidArgumentError("no valid signing keys")
 		}
 		signer = signKey.PrivateKey
+		if signer == nil {
+			return nil, errors.InvalidArgumentError("no private key in signing key")
+		}
 		if signer.Encrypted {
 			return nil, errors.InvalidArgumentError("signing key must be decrypted")
 		}
diff --git a/go/src/golang.org/x/crypto/poly1305/const_amd64.s b/go/src/golang.org/x/crypto/poly1305/const_amd64.s
index 33fcd6e..8e861f3 100644
--- a/go/src/golang.org/x/crypto/poly1305/const_amd64.s
+++ b/go/src/golang.org/x/crypto/poly1305/const_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 DATA ·SCALE(SB)/8, $0x37F4000000000000
 GLOBL ·SCALE(SB), 8, $8
diff --git a/go/src/golang.org/x/crypto/poly1305/poly1305_amd64.s b/go/src/golang.org/x/crypto/poly1305/poly1305_amd64.s
index b9ad0ba..f8d4ee9 100644
--- a/go/src/golang.org/x/crypto/poly1305/poly1305_amd64.s
+++ b/go/src/golang.org/x/crypto/poly1305/poly1305_amd64.s
@@ -5,7 +5,7 @@
 // This code was translated into a form compatible with 6a from the public
 // domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 // func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key)
 TEXT ·poly1305(SB),0,$224-32
diff --git a/go/src/golang.org/x/crypto/poly1305/poly1305_arm.s b/go/src/golang.org/x/crypto/poly1305/poly1305_arm.s
new file mode 100644
index 0000000..c9ceaeb
--- /dev/null
+++ b/go/src/golang.org/x/crypto/poly1305/poly1305_arm.s
@@ -0,0 +1,331 @@
+// Copyright 2015 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.
+
+// This code was translated into a form compatible with 5a from the public
+// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
+
+// +build arm,!gccgo,!appengine
+
+DATA poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
+DATA poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
+DATA poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
+DATA poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
+DATA poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
+GLOBL poly1305_init_constants_armv6<>(SB), 8, $20
+
+// Warning: the linker may use R11 to synthesize certain instructions. Please
+// take care and verify that no synthetic instructions use it.
+
+TEXT poly1305_init_ext_armv6<>(SB),4,$-4
+  MOVM.DB.W [R4-R11], (R13)
+  MOVM.IA.W (R1), [R2-R5]
+  MOVW $poly1305_init_constants_armv6<>(SB), R7
+  MOVW R2, R8
+  MOVW R2>>26, R9
+  MOVW R3>>20, g
+  MOVW R4>>14, R11
+  MOVW R5>>8, R12
+  ORR R3<<6, R9, R9
+  ORR R4<<12, g, g
+  ORR R5<<18, R11, R11
+  MOVM.IA (R7), [R2-R6]
+  AND R8, R2, R2
+  AND R9, R3, R3
+  AND g, R4, R4
+  AND R11, R5, R5
+  AND R12, R6, R6
+  MOVM.IA.W [R2-R6], (R0)
+  EOR R2, R2, R2
+  EOR R3, R3, R3
+  EOR R4, R4, R4
+  EOR R5, R5, R5
+  EOR R6, R6, R6
+  MOVM.IA.W [R2-R6], (R0)
+  MOVM.IA.W (R1), [R2-R5]
+  MOVM.IA [R2-R6], (R0)
+  MOVM.IA.W (R13), [R4-R11]
+  RET
+
+TEXT poly1305_blocks_armv6<>(SB),4,$-4
+  MOVM.DB.W [R4, R5, R6, R7, R8, R9, g, R11, R14], (R13)
+  SUB $128, R13
+  MOVW R0, 36(R13)
+  MOVW R1, 40(R13)
+  MOVW R2, 44(R13)
+  MOVW R1, R14
+  MOVW R2, R12
+  MOVW 56(R0), R8
+  WORD $0xe1180008 // TST R8, R8 not working see issue 5921
+  EOR R6, R6, R6
+  MOVW.EQ $(1<<24), R6
+  MOVW R6, 32(R13)
+  ADD $64, R13, g
+  MOVM.IA (R0), [R0-R9]
+  MOVM.IA [R0-R4], (g)
+  CMP $16, R12
+  BLO poly1305_blocks_armv6_done
+poly1305_blocks_armv6_mainloop:
+  MOVM.IA.W (R14), [R0-R3]
+  MOVW R0>>26, g
+  MOVW R1>>20, R11
+  MOVW R2>>14, R12
+  MOVW R14, 40(R13)
+  MOVW R3>>8, R4
+  ORR R1<<6, g, g
+  ORR R2<<12, R11, R11
+  ORR R3<<18, R12, R12
+  BIC $0xfc000000, R0, R0
+  BIC $0xfc000000, g, g
+  MOVW 32(R13), R3
+  BIC $0xfc000000, R11, R11
+  BIC $0xfc000000, R12, R12
+  ADD R0, R5, R5
+  ADD g, R6, R6
+  ORR R3, R4, R4
+  ADD R11, R7, R7
+  ADD $64, R13, R14
+  ADD R12, R8, R8
+  ADD R4, R9, R9
+  MOVM.IA (R14), [R0-R4]
+  MULLU R4, R5, (R11, g)
+  MULLU R3, R5, (R14, R12)
+  MULALU R3, R6, (R11, g)
+  MULALU R2, R6, (R14, R12)
+  MULALU R2, R7, (R11, g)
+  MULALU R1, R7, (R14, R12)
+  ADD R4<<2, R4, R4
+  ADD R3<<2, R3, R3
+  MULALU R1, R8, (R11, g)
+  MULALU R0, R8, (R14, R12)
+  MULALU R0, R9, (R11, g)
+  MULALU R4, R9, (R14, R12)
+  MOVW g, 24(R13)
+  MOVW R11, 28(R13)
+  MOVW R12, 16(R13)
+  MOVW R14, 20(R13)
+  MULLU R2, R5, (R11, g)
+  MULLU R1, R5, (R14, R12)
+  MULALU R1, R6, (R11, g)
+  MULALU R0, R6, (R14, R12)
+  MULALU R0, R7, (R11, g)
+  MULALU R4, R7, (R14, R12)
+  ADD R2<<2, R2, R2
+  ADD R1<<2, R1, R1
+  MULALU R4, R8, (R11, g)
+  MULALU R3, R8, (R14, R12)
+  MULALU R3, R9, (R11, g)
+  MULALU R2, R9, (R14, R12)
+  MOVW g, 8(R13)
+  MOVW R11, 12(R13)
+  MOVW R12, 0(R13)
+  MOVW R14, w+4(SP)
+  MULLU R0, R5, (R11, g)
+  MULALU R4, R6, (R11, g)
+  MULALU R3, R7, (R11, g)
+  MULALU R2, R8, (R11, g)
+  MULALU R1, R9, (R11, g)
+  MOVM.IA (R13), [R0-R7]
+  MOVW g>>26, R12
+  MOVW R4>>26, R14
+  ORR R11<<6, R12, R12
+  ORR R5<<6, R14, R14
+  BIC $0xfc000000, g, g
+  BIC $0xfc000000, R4, R4
+  ADD.S R12, R0, R0
+  ADC $0, R1, R1
+  ADD.S R14, R6, R6
+  ADC $0, R7, R7
+  MOVW R0>>26, R12
+  MOVW R6>>26, R14
+  ORR R1<<6, R12, R12
+  ORR R7<<6, R14, R14
+  BIC $0xfc000000, R0, R0
+  BIC $0xfc000000, R6, R6
+  ADD R14<<2, R14, R14
+  ADD.S R12, R2, R2
+  ADC $0, R3, R3
+  ADD R14, g, g
+  MOVW R2>>26, R12
+  MOVW g>>26, R14
+  ORR R3<<6, R12, R12
+  BIC $0xfc000000, g, R5
+  BIC $0xfc000000, R2, R7
+  ADD R12, R4, R4
+  ADD R14, R0, R0
+  MOVW R4>>26, R12
+  BIC $0xfc000000, R4, R8
+  ADD R12, R6, R9
+  MOVW w+44(SP), R12
+  MOVW w+40(SP), R14
+  MOVW R0, R6
+  CMP $32, R12
+  SUB $16, R12, R12
+  MOVW R12, 44(R13)
+  BHS poly1305_blocks_armv6_mainloop
+poly1305_blocks_armv6_done:
+  MOVW 36(R13), R12
+  MOVW R5, 20(R12)
+  MOVW R6, 24(R12)
+  MOVW R7, 28(R12)
+  MOVW R8, 32(R12)
+  MOVW R9, 36(R12)
+  ADD $128, R13, R13
+  MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, g, R11, R14]
+  RET
+
+TEXT poly1305_finish_ext_armv6<>(SB),4,$-4
+  MOVM.DB.W [R4, R5, R6, R7, R8, R9, g, R11, R14], (R13)
+  SUB $16, R13, R13
+  MOVW R0, R5
+  MOVW R1, R6
+  MOVW R2, R7
+  MOVW R3, R8
+  AND.S R2, R2, R2
+  BEQ poly1305_finish_ext_armv6_noremaining
+  EOR R0, R0
+  MOVW R13, R9
+  MOVW R0, 0(R13)
+  MOVW R0, 4(R13)
+  MOVW R0, 8(R13)
+  MOVW R0, 12(R13)
+  WORD $0xe3120008 // TST R2, #8 not working see issue 5921
+  BEQ poly1305_finish_ext_armv6_skip8
+  MOVM.IA.W (R1), [g-R11]
+  MOVM.IA.W [g-R11], (R9)
+poly1305_finish_ext_armv6_skip8:
+  WORD $0xe3120004 // TST $4, R2 not working see issue 5921
+  BEQ poly1305_finish_ext_armv6_skip4
+  MOVW.P 4(R1), g
+  MOVW.P g, 4(R9)
+poly1305_finish_ext_armv6_skip4:
+  WORD $0xe3120002 // TST $2, R2 not working see issue 5921
+  BEQ poly1305_finish_ext_armv6_skip2
+  MOVHU.P 2(R1), g
+  MOVH.P g, 2(R9)
+poly1305_finish_ext_armv6_skip2:
+  WORD $0xe3120001 // TST $1, R2 not working see issue 5921
+  BEQ poly1305_finish_ext_armv6_skip1
+  MOVBU.P 1(R1), g
+  MOVBU.P g, 1(R9)
+poly1305_finish_ext_armv6_skip1:
+  MOVW $1, R11
+  MOVBU R11, 0(R9)
+  MOVW R11, 56(R5)
+  MOVW R5, R0
+  MOVW R13, R1
+  MOVW $16, R2
+  BL poly1305_blocks_armv6<>(SB)
+poly1305_finish_ext_armv6_noremaining:
+  MOVW 20(R5), R0
+  MOVW 24(R5), R1
+  MOVW 28(R5), R2
+  MOVW 32(R5), R3
+  MOVW 36(R5), R4
+  MOVW R4>>26, R12
+  BIC $0xfc000000, R4, R4
+  ADD R12<<2, R12, R12
+  ADD R12, R0, R0
+  MOVW R0>>26, R12
+  BIC $0xfc000000, R0, R0
+  ADD R12, R1, R1
+  MOVW R1>>26, R12
+  BIC $0xfc000000, R1, R1
+  ADD R12, R2, R2
+  MOVW R2>>26, R12
+  BIC $0xfc000000, R2, R2
+  ADD R12, R3, R3
+  MOVW R3>>26, R12
+  BIC $0xfc000000, R3, R3
+  ADD R12, R4, R4
+  ADD $5, R0, R6
+  MOVW R6>>26, R12
+  BIC $0xfc000000, R6, R6
+  ADD R12, R1, R7
+  MOVW R7>>26, R12
+  BIC $0xfc000000, R7, R7
+  ADD R12, R2, g
+  MOVW g>>26, R12
+  BIC $0xfc000000, g, g
+  ADD R12, R3, R11
+  MOVW $-(1<<26), R12
+  ADD R11>>26, R12, R12
+  BIC $0xfc000000, R11, R11
+  ADD R12, R4, R14
+  MOVW R14>>31, R12
+  SUB $1, R12
+  AND R12, R6, R6
+  AND R12, R7, R7
+  AND R12, g, g
+  AND R12, R11, R11
+  AND R12, R14, R14
+  MVN R12, R12
+  AND R12, R0, R0
+  AND R12, R1, R1
+  AND R12, R2, R2
+  AND R12, R3, R3
+  AND R12, R4, R4
+  ORR R6, R0, R0
+  ORR R7, R1, R1
+  ORR g, R2, R2
+  ORR R11, R3, R3
+  ORR R14, R4, R4
+  ORR R1<<26, R0, R0
+  MOVW R1>>6, R1
+  ORR R2<<20, R1, R1
+  MOVW R2>>12, R2
+  ORR R3<<14, R2, R2
+  MOVW R3>>18, R3
+  ORR R4<<8, R3, R3
+  MOVW 40(R5), R6
+  MOVW 44(R5), R7
+  MOVW 48(R5), g
+  MOVW 52(R5), R11
+  ADD.S R6, R0, R0
+  ADC.S R7, R1, R1
+  ADC.S g, R2, R2
+  ADC.S R11, R3, R3
+  MOVM.IA [R0-R3], (R8)
+  MOVW R5, R12
+  EOR R0, R0, R0
+  EOR R1, R1, R1
+  EOR R2, R2, R2
+  EOR R3, R3, R3
+  EOR R4, R4, R4
+  EOR R5, R5, R5
+  EOR R6, R6, R6
+  EOR R7, R7, R7
+  MOVM.IA.W [R0-R7], (R12)
+  MOVM.IA [R0-R7], (R12)
+  ADD $16, R13, R13
+  MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, g, R11, R14]
+  RET
+
+// func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key)
+TEXT ·poly1305_auth_armv6(SB),0,$280-16
+  MOVW  out+0(FP), R4
+  MOVW  m+4(FP), R5
+  MOVW  mlen+8(FP), R6
+  MOVW  key+12(FP), R7
+
+  MOVW R13, R8
+  BIC $63, R13
+  SUB $64, R13, R13
+  MOVW  R13, R0
+  MOVW  R7, R1
+  BL poly1305_init_ext_armv6<>(SB)
+  BIC.S $15, R6, R2
+  BEQ poly1305_auth_armv6_noblocks
+  MOVW R13, R0
+  MOVW R5, R1
+  ADD R2, R5, R5
+  SUB R2, R6, R6
+  BL poly1305_blocks_armv6<>(SB)
+poly1305_auth_armv6_noblocks:
+  MOVW R13, R0
+  MOVW R5, R1
+  MOVW R6, R2
+  MOVW R4, R3
+  BL poly1305_finish_ext_armv6<>(SB)
+  MOVW R8, R13
+  RET
diff --git a/go/src/golang.org/x/crypto/poly1305/sum_amd64.go b/go/src/golang.org/x/crypto/poly1305/sum_amd64.go
index eb22ca1..6775c70 100644
--- a/go/src/golang.org/x/crypto/poly1305/sum_amd64.go
+++ b/go/src/golang.org/x/crypto/poly1305/sum_amd64.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64,!gccgo
+// +build amd64,!gccgo,!appengine
 
 package poly1305
 
diff --git a/go/src/golang.org/x/crypto/poly1305/sum_arm.go b/go/src/golang.org/x/crypto/poly1305/sum_arm.go
new file mode 100644
index 0000000..50b979c
--- /dev/null
+++ b/go/src/golang.org/x/crypto/poly1305/sum_arm.go
@@ -0,0 +1,24 @@
+// Copyright 2015 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.
+
+// +build arm,!gccgo,!appengine
+
+package poly1305
+
+// This function is implemented in poly1305_arm.s
+
+//go:noescape
+
+func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+	var mPtr *byte
+	if len(m) > 0 {
+		mPtr = &m[0]
+	}
+	poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
+}
diff --git a/go/src/golang.org/x/crypto/poly1305/sum_ref.go b/go/src/golang.org/x/crypto/poly1305/sum_ref.go
index 12568a2..0b24fc7 100644
--- a/go/src/golang.org/x/crypto/poly1305/sum_ref.go
+++ b/go/src/golang.org/x/crypto/poly1305/sum_ref.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64 gccgo
+// +build !amd64,!arm gccgo appengine
 
 package poly1305
 
diff --git a/go/src/golang.org/x/crypto/sha3/doc.go b/go/src/golang.org/x/crypto/sha3/doc.go
index 027c8ad..a0ee3ae 100644
--- a/go/src/golang.org/x/crypto/sha3/doc.go
+++ b/go/src/golang.org/x/crypto/sha3/doc.go
@@ -12,7 +12,8 @@
 // Guidance
 //
 // If you aren't sure what function you need, use SHAKE256 with at least 64
-// bytes of output.
+// bytes of output. The SHAKE instances are faster than the SHA3 instances;
+// the latter have to allocate memory to conform to the hash.Hash interface.
 //
 // If you need a secret-key MAC (message authentication code), prepend the
 // secret key to the input, hash with SHAKE256 and read at least 32 bytes of
@@ -21,45 +22,42 @@
 //
 // Security strengths
 //
-// The SHA3-x functions have a security strength against preimage attacks of x
-// bits. Since they only produce x bits of output, their collision-resistance
-// is only x/2 bits.
+// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
+// strength against preimage attacks of x bits. Since they only produce "x"
+// bits of output, their collision-resistance is only "x/2" bits.
 //
-// The SHAKE-x functions have a generic security strength of x bits against
-// all attacks, provided that at least 2x bits of their output is used.
-// Requesting more than 2x bits of output does not increase the collision-
-// resistance of the SHAKE functions.
+// The SHAKE-256 and -128 functions have a generic security strength of 256 and
+// 128 bits against all attacks, provided that at least 2x bits of their output
+// is used.  Requesting more than 64 or 32 bytes of output, respectively, does
+// not increase the collision-resistance of the SHAKE functions.
 //
 //
 // The sponge construction
 //
-// A sponge builds a pseudo-random function from a pseudo-random permutation,
-// by applying the permutation to a state of "rate + capacity" bytes, but
-// hiding "capacity" of the bytes.
+// A sponge builds a pseudo-random function from a public pseudo-random
+// permutation, by applying the permutation to a state of "rate + capacity"
+// bytes, but hiding "capacity" of the bytes.
 //
 // A sponge starts out with a zero state. To hash an input using a sponge, up
 // to "rate" bytes of the input are XORed into the sponge's state. The sponge
-// has thus been "filled up" and the permutation is applied. This process is
+// is then "full" and the permutation is applied to "empty" it. This process is
 // repeated until all the input has been "absorbed". The input is then padded.
-// The digest is "squeezed" from the sponge by the same method, except that
-// output is copied out.
+// The digest is "squeezed" from the sponge in the same way, except that output
+// output is copied out instead of input being XORed in.
 //
 // A sponge is parameterized by its generic security strength, which is equal
 // to half its capacity; capacity + rate is equal to the permutation's width.
-//
 // Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
-// that security_strength == (1600 - bitrate) / 2.
+// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
 //
 //
-// Recommendations, detailed
+// Recommendations
 //
 // The SHAKE functions are recommended for most new uses. They can produce
 // output of arbitrary length. SHAKE256, with an output length of at least
-// 64 bytes, provides 256-bit security against all attacks.
-//
-// The Keccak team recommends SHAKE256 for most applications upgrading from
-// SHA2-512. (NIST chose a much stronger, but much slower, sponge instance
-// for SHA3-512.)
+// 64 bytes, provides 256-bit security against all attacks.  The Keccak team
+// recommends it for most applications upgrading from SHA2-512. (NIST chose a
+// much stronger, but much slower, sponge instance for SHA3-512.)
 //
 // The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
 // They produce output of the same length, with the same security strengths
diff --git a/go/src/golang.org/x/crypto/sha3/sha3.go b/go/src/golang.org/x/crypto/sha3/sha3.go
index 8d77568..c8fd31c 100644
--- a/go/src/golang.org/x/crypto/sha3/sha3.go
+++ b/go/src/golang.org/x/crypto/sha3/sha3.go
@@ -4,10 +4,6 @@
 
 package sha3
 
-import (
-	"encoding/binary"
-)
-
 // spongeDirection indicates the direction bytes are flowing through the sponge.
 type spongeDirection int
 
@@ -30,25 +26,25 @@
 	buf  []byte     // points into storage
 	rate int        // the number of bytes of state to use
 
-	// dsbyte contains the "domain separation" value and the first bit of
-	// the padding. In sections 6.1 and 6.2 of [1], the SHA-3 and SHAKE
-	// functions are defined with bits appended to the message: SHA-3
-	// functions have 01 and SHAKE functions have 1111. Because of the way
-	// that bits are numbered from the LSB upwards, that ends up as
-	// 00000010b and 00001111b, respectively. Then the padding rule from
-	// section 5.1 is applied to pad to a multiple of the rate, which
-	// involves adding a 1 bit, zero or more zero bits and then a final one
-	// bit. The first one bit from the padding is merged into the dsbyte
-	// value giving 00000110b (0x06) and 00011111b (0x1f), respectively.
-	//
-	// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf,
+	// dsbyte contains the "domain separation" bits and the first bit of
+	// the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
+	// SHA-3 and SHAKE functions by appending bitstrings to the message.
+	// Using a little-endian bit-ordering convention, these are "01" for SHA-3
+	// and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
+	// padding rule from section 5.1 is applied to pad the message to a multiple
+	// of the rate, which involves adding a "1" bit, zero or more "0" bits, and
+	// a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
+	// giving 00000110b (0x06) and 00011111b (0x1f).
+	// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
+	//     "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
+	//      Extendable-Output Functions (May 2014)"
 	dsbyte  byte
 	storage [maxRate]byte
 
 	// Specific to SHA-3 and SHAKE.
 	fixedOutput bool            // whether this is a fixed-ouput-length instance
 	outputLen   int             // the default output size in bytes
-	state       spongeDirection // current direction of the sponge
+	state       spongeDirection // whether the sponge is absorbing or squeezing
 }
 
 // BlockSize returns the rate of sponge underlying this hash function.
@@ -79,35 +75,6 @@
 	return &ret
 }
 
-// xorIn xors a buffer into the state, byte-swapping to
-// little-endian as necessary; it returns the number of bytes
-// copied, including any zeros appended to the bytestring.
-func (d *state) xorIn(buf []byte) {
-	n := len(buf) / 8
-
-	for i := 0; i < n; i++ {
-		a := binary.LittleEndian.Uint64(buf)
-		d.a[i] ^= a
-		buf = buf[8:]
-	}
-	if len(buf) != 0 {
-		// XOR in the last partial ulint64.
-		a := uint64(0)
-		for i, v := range buf {
-			a |= uint64(v) << uint64(8*i)
-		}
-		d.a[n] ^= a
-	}
-}
-
-// copyOut copies ulint64s to a byte buffer.
-func (d *state) copyOut(b []byte) {
-	for i := 0; len(b) >= 8; i++ {
-		binary.LittleEndian.PutUint64(b, d.a[i])
-		b = b[8:]
-	}
-}
-
 // permute applies the KeccakF-1600 permutation. It handles
 // any input-output buffering.
 func (d *state) permute() {
@@ -115,7 +82,7 @@
 	case spongeAbsorbing:
 		// If we're absorbing, we need to xor the input into the state
 		// before applying the permutation.
-		d.xorIn(d.buf)
+		xorIn(d, d.buf)
 		d.buf = d.storage[:0]
 		keccakF1600(&d.a)
 	case spongeSqueezing:
@@ -123,7 +90,7 @@
 		// copying more output.
 		keccakF1600(&d.a)
 		d.buf = d.storage[:d.rate]
-		d.copyOut(d.buf)
+		copyOut(d, d.buf)
 	}
 }
 
@@ -151,7 +118,7 @@
 	d.permute()
 	d.state = spongeSqueezing
 	d.buf = d.storage[:d.rate]
-	d.copyOut(d.buf)
+	copyOut(d, d.buf)
 }
 
 // Write absorbs more data into the hash's state. It produces an error
@@ -168,7 +135,7 @@
 	for len(p) > 0 {
 		if len(d.buf) == 0 && len(p) >= d.rate {
 			// The fast path; absorb a full "rate" bytes of input and apply the permutation.
-			d.xorIn(p[:d.rate])
+			xorIn(d, p[:d.rate])
 			p = p[d.rate:]
 			keccakF1600(&d.a)
 		} else {
diff --git a/go/src/golang.org/x/crypto/sha3/sha3_test.go b/go/src/golang.org/x/crypto/sha3/sha3_test.go
index 6f84863..caf72f2 100644
--- a/go/src/golang.org/x/crypto/sha3/sha3_test.go
+++ b/go/src/golang.org/x/crypto/sha3/sha3_test.go
@@ -7,8 +7,8 @@
 // Tests include all the ShortMsgKATs provided by the Keccak team at
 // https://github.com/gvanas/KeccakCodePackage
 //
-// They only include the zero-bit case of the utterly useless bitwise
-// testvectors published by NIST in the draft of FIPS-202.
+// They only include the zero-bit case of the bitwise testvectors
+// published by NIST in the draft of FIPS-202.
 
 import (
 	"bytes"
@@ -23,7 +23,7 @@
 
 const (
 	testString  = "brekeccakkeccak koax koax"
-	katFilename = "keccakKats.json.deflate"
+	katFilename = "testdata/keccakKats.json.deflate"
 )
 
 // Internal-use instances of SHAKE used to test against KATs.
@@ -46,14 +46,14 @@
 	"SHAKE256": newHashShake256,
 }
 
-// testShakes contains functions returning ShakeHash instances for
+// testShakes contains functions that return ShakeHash instances for
 // testing the ShakeHash-specific interface.
 var testShakes = map[string]func() ShakeHash{
 	"SHAKE128": NewShake128,
 	"SHAKE256": NewShake256,
 }
 
-// decodeHex converts an hex-encoded string into a raw byte string.
+// decodeHex converts a hex-encoded string into a raw byte string.
 func decodeHex(s string) []byte {
 	b, err := hex.DecodeString(s)
 	if err != nil {
@@ -71,135 +71,146 @@
 	}
 }
 
+func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
+	xorInOrig, copyOutOrig := xorIn, copyOut
+	xorIn, copyOut = xorInGeneric, copyOutGeneric
+	testf("generic")
+	if xorImplementationUnaligned != "generic" {
+		xorIn, copyOut = xorInUnaligned, copyOutUnaligned
+		testf("unaligned")
+	}
+	xorIn, copyOut = xorInOrig, copyOutOrig
+}
+
 // TestKeccakKats tests the SHA-3 and Shake implementations against all the
 // ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
 // (The testvectors are stored in keccakKats.json.deflate due to their length.)
 func TestKeccakKats(t *testing.T) {
-	// Read the KATs.
-	deflated, err := os.Open(katFilename)
-	if err != nil {
-		t.Errorf("Error opening %s: %s", katFilename, err)
-	}
-	file := flate.NewReader(deflated)
-	dec := json.NewDecoder(file)
-	var katSet KeccakKats
-	err = dec.Decode(&katSet)
-	if err != nil {
-		t.Errorf("%s", err)
-	}
+	testUnalignedAndGeneric(t, func(impl string) {
+		// Read the KATs.
+		deflated, err := os.Open(katFilename)
+		if err != nil {
+			t.Errorf("error opening %s: %s", katFilename, err)
+		}
+		file := flate.NewReader(deflated)
+		dec := json.NewDecoder(file)
+		var katSet KeccakKats
+		err = dec.Decode(&katSet)
+		if err != nil {
+			t.Errorf("error decoding KATs: %s", err)
+		}
 
-	// Do the KATs.
-	for functionName, kats := range katSet.Kats {
-		d := testDigests[functionName]()
-		t.Logf("%s", functionName)
-		for _, kat := range kats {
-			d.Reset()
-			in, err := hex.DecodeString(kat.Message)
-			if err != nil {
-				t.Errorf("%s", err)
-			}
-			d.Write(in[:kat.Length/8])
-			got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
-			want := kat.Digest
-			if got != want {
-				t.Errorf("function=%s, length=%d\nmessage:\n  %s\ngot:\n  %s\nwanted:\n %s",
-					functionName, kat.Length, kat.Message, got, want)
-				t.Logf("wanted %+v", kat)
-				t.FailNow()
+		// Do the KATs.
+		for functionName, kats := range katSet.Kats {
+			d := testDigests[functionName]()
+			for _, kat := range kats {
+				d.Reset()
+				in, err := hex.DecodeString(kat.Message)
+				if err != nil {
+					t.Errorf("error decoding KAT: %s", err)
+				}
+				d.Write(in[:kat.Length/8])
+				got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
+				if got != kat.Digest {
+					t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n  %s\ngot:\n  %s\nwanted:\n %s",
+						functionName, impl, kat.Length, kat.Message, got, kat.Digest)
+					t.Logf("wanted %+v", kat)
+					t.FailNow()
+				}
+				continue
 			}
 		}
-	}
+	})
 }
 
 // TestUnalignedWrite tests that writing data in an arbitrary pattern with
 // small input buffers.
-func TestUnalignedWrite(t *testing.T) {
-	buf := sequentialBytes(0x10000)
-	for alg, df := range testDigests {
-		d := df()
-		d.Reset()
-		d.Write(buf)
-		want := d.Sum(nil)
-		d.Reset()
-		for i := 0; i < len(buf); {
-			// Cycle through offsets which make a 137 byte sequence.
-			// Because 137 is prime this sequence should exercise all corner cases.
-			offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
-			for _, j := range offsets {
-				if v := len(buf) - i; v < j {
-					j = v
+func testUnalignedWrite(t *testing.T) {
+	testUnalignedAndGeneric(t, func(impl string) {
+		buf := sequentialBytes(0x10000)
+		for alg, df := range testDigests {
+			d := df()
+			d.Reset()
+			d.Write(buf)
+			want := d.Sum(nil)
+			d.Reset()
+			for i := 0; i < len(buf); {
+				// Cycle through offsets which make a 137 byte sequence.
+				// Because 137 is prime this sequence should exercise all corner cases.
+				offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
+				for _, j := range offsets {
+					if v := len(buf) - i; v < j {
+						j = v
+					}
+					d.Write(buf[i : i+j])
+					i += j
 				}
-				d.Write(buf[i : i+j])
-				i += j
+			}
+			got := d.Sum(nil)
+			if !bytes.Equal(got, want) {
+				t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
 			}
 		}
-		got := d.Sum(nil)
-		if !bytes.Equal(got, want) {
-			t.Errorf("Unaligned writes, alg=%s\ngot %q, want %q", alg, got, want)
-		}
-	}
+	})
 }
 
-// Test that appending works when reallocation is necessary.
+// TestAppend checks that appending works when reallocation is necessary.
 func TestAppend(t *testing.T) {
-	d := New224()
+	testUnalignedAndGeneric(t, func(impl string) {
+		d := New224()
 
-	for capacity := 2; capacity < 64; capacity += 64 {
-		// The first time around the loop, Sum will have to reallocate.
-		// The second time, it will not.
-		buf := make([]byte, 2, capacity)
-		d.Reset()
+		for capacity := 2; capacity <= 66; capacity += 64 {
+			// The first time around the loop, Sum will have to reallocate.
+			// The second time, it will not.
+			buf := make([]byte, 2, capacity)
+			d.Reset()
+			d.Write([]byte{0xcc})
+			buf = d.Sum(buf)
+			expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
+			if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
+				t.Errorf("got %s, want %s", got, expected)
+			}
+		}
+	})
+}
+
+// TestAppendNoRealloc tests that appending works when no reallocation is necessary.
+func TestAppendNoRealloc(t *testing.T) {
+	testUnalignedAndGeneric(t, func(impl string) {
+		buf := make([]byte, 1, 200)
+		d := New224()
 		d.Write([]byte{0xcc})
 		buf = d.Sum(buf)
-		expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
+		expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
 		if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
-			t.Errorf("got %s, want %s", got, expected)
+			t.Errorf("%s: got %s, want %s", impl, got, expected)
 		}
-	}
-}
-
-// Test that appending works when no reallocation is necessary.
-func TestAppendNoRealloc(t *testing.T) {
-	buf := make([]byte, 1, 200)
-	d := New224()
-	d.Write([]byte{0xcc})
-	buf = d.Sum(buf)
-	expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
-	if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
-		t.Errorf("got %s, want %s", got, expected)
-	}
+	})
 }
 
 // TestSqueezing checks that squeezing the full output a single time produces
 // the same output as repeatedly squeezing the instance.
 func TestSqueezing(t *testing.T) {
-	for functionName, newShakeHash := range testShakes {
-		t.Logf("%s", functionName)
-		d0 := newShakeHash()
-		d0.Write([]byte(testString))
-		ref := make([]byte, 32)
-		d0.Read(ref)
+	testUnalignedAndGeneric(t, func(impl string) {
+		for functionName, newShakeHash := range testShakes {
+			d0 := newShakeHash()
+			d0.Write([]byte(testString))
+			ref := make([]byte, 32)
+			d0.Read(ref)
 
-		d1 := newShakeHash()
-		d1.Write([]byte(testString))
-		var multiple []byte
-		for _ = range ref {
-			one := make([]byte, 1)
-			d1.Read(one)
-			multiple = append(multiple, one...)
+			d1 := newShakeHash()
+			d1.Write([]byte(testString))
+			var multiple []byte
+			for _ = range ref {
+				one := make([]byte, 1)
+				d1.Read(one)
+				multiple = append(multiple, one...)
+			}
+			if !bytes.Equal(ref, multiple) {
+				t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
+			}
 		}
-		if !bytes.Equal(ref, multiple) {
-			t.Errorf("squeezing %d bytes one at a time failed", len(ref))
-		}
-	}
-}
-
-func TestReadSimulation(t *testing.T) {
-	d := NewShake256()
-	d.Write(nil)
-	dwr := make([]byte, 32)
-	d.Read(dwr)
-
+	})
 }
 
 // sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
@@ -221,29 +232,75 @@
 	}
 }
 
-// benchmarkBulkHash tests the speed to hash a buffer of buflen.
-func benchmarkBulkHash(b *testing.B, h hash.Hash, size int) {
+// benchmarkHash tests the speed to hash num buffers of buflen each.
+func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
 	b.StopTimer()
 	h.Reset()
 	data := sequentialBytes(size)
-	b.SetBytes(int64(size))
+	b.SetBytes(int64(size * num))
 	b.StartTimer()
 
 	var state []byte
 	for i := 0; i < b.N; i++ {
-		h.Write(data)
+		for j := 0; j < num; j++ {
+			h.Write(data)
+		}
 		state = h.Sum(state[:0])
 	}
 	b.StopTimer()
 	h.Reset()
 }
 
-func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkBulkHash(b, New512(), 1350) }
-func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkBulkHash(b, New384(), 1350) }
-func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkBulkHash(b, New256(), 1350) }
-func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkBulkHash(b, New224(), 1350) }
-func BenchmarkShake256_MTU(b *testing.B) { benchmarkBulkHash(b, newHashShake256(), 1350) }
-func BenchmarkShake128_MTU(b *testing.B) { benchmarkBulkHash(b, newHashShake128(), 1350) }
+// benchmarkShake is specialized to the Shake instances, which don't
+// require a copy on reading output.
+func benchmarkShake(b *testing.B, h ShakeHash, size, num int) {
+	b.StopTimer()
+	h.Reset()
+	data := sequentialBytes(size)
+	d := make([]byte, 32)
 
-func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkBulkHash(b, New512(), 1<<20) }
-func BenchmarkShake256_1MiB(b *testing.B) { benchmarkBulkHash(b, newHashShake256(), 1<<20) }
+	b.SetBytes(int64(size * num))
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		h.Reset()
+		for j := 0; j < num; j++ {
+			h.Write(data)
+		}
+		h.Read(d)
+	}
+}
+
+func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) }
+func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) }
+func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) }
+func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) }
+
+func BenchmarkShake128_MTU(b *testing.B)  { benchmarkShake(b, NewShake128(), 1350, 1) }
+func BenchmarkShake256_MTU(b *testing.B)  { benchmarkShake(b, NewShake256(), 1350, 1) }
+func BenchmarkShake256_16x(b *testing.B)  { benchmarkShake(b, NewShake256(), 16, 1024) }
+func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
+
+func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }
+
+func Example_sum() {
+	buf := []byte("some data to hash")
+	// A hash needs to be 64 bytes long to have 256-bit collision resistance.
+	h := make([]byte, 64)
+	// Compute a 64-byte hash of buf and put it in h.
+	ShakeSum256(h, buf)
+}
+
+func Example_mac() {
+	k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long")
+	buf := []byte("and this is some data to authenticate")
+	// A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key.
+	h := make([]byte, 32)
+	d := NewShake256()
+	// Write the key into the hash.
+	d.Write(k)
+	// Now write the data.
+	d.Write(buf)
+	// Read 32 bytes of output from the hash into h.
+	d.Read(h)
+}
diff --git a/go/src/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate b/go/src/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
new file mode 100644
index 0000000..62e85ae
--- /dev/null
+++ b/go/src/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
Binary files differ
diff --git a/go/src/golang.org/x/crypto/sha3/xor.go b/go/src/golang.org/x/crypto/sha3/xor.go
new file mode 100644
index 0000000..d622979
--- /dev/null
+++ b/go/src/golang.org/x/crypto/sha3/xor.go
@@ -0,0 +1,16 @@
+// Copyright 2015 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.
+
+// +build !amd64,!386 appengine
+
+package sha3
+
+var (
+	xorIn            = xorInGeneric
+	copyOut          = copyOutGeneric
+	xorInUnaligned   = xorInGeneric
+	copyOutUnaligned = copyOutGeneric
+)
+
+const xorImplementationUnaligned = "generic"
diff --git a/go/src/golang.org/x/crypto/sha3/xor_generic.go b/go/src/golang.org/x/crypto/sha3/xor_generic.go
new file mode 100644
index 0000000..fd35f02
--- /dev/null
+++ b/go/src/golang.org/x/crypto/sha3/xor_generic.go
@@ -0,0 +1,28 @@
+// Copyright 2015 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 sha3
+
+import "encoding/binary"
+
+// xorInGeneric xors the bytes in buf into the state; it
+// makes no non-portable assumptions about memory layout
+// or alignment.
+func xorInGeneric(d *state, buf []byte) {
+	n := len(buf) / 8
+
+	for i := 0; i < n; i++ {
+		a := binary.LittleEndian.Uint64(buf)
+		d.a[i] ^= a
+		buf = buf[8:]
+	}
+}
+
+// copyOutGeneric copies ulint64s to a byte buffer.
+func copyOutGeneric(d *state, b []byte) {
+	for i := 0; len(b) >= 8; i++ {
+		binary.LittleEndian.PutUint64(b, d.a[i])
+		b = b[8:]
+	}
+}
diff --git a/go/src/golang.org/x/crypto/sha3/xor_unaligned.go b/go/src/golang.org/x/crypto/sha3/xor_unaligned.go
new file mode 100644
index 0000000..c7851a1
--- /dev/null
+++ b/go/src/golang.org/x/crypto/sha3/xor_unaligned.go
@@ -0,0 +1,58 @@
+// Copyright 2015 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.
+
+// +build amd64 386
+// +build !appengine
+
+package sha3
+
+import "unsafe"
+
+func xorInUnaligned(d *state, buf []byte) {
+	bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))
+	n := len(buf)
+	if n >= 72 {
+		d.a[0] ^= bw[0]
+		d.a[1] ^= bw[1]
+		d.a[2] ^= bw[2]
+		d.a[3] ^= bw[3]
+		d.a[4] ^= bw[4]
+		d.a[5] ^= bw[5]
+		d.a[6] ^= bw[6]
+		d.a[7] ^= bw[7]
+		d.a[8] ^= bw[8]
+	}
+	if n >= 104 {
+		d.a[9] ^= bw[9]
+		d.a[10] ^= bw[10]
+		d.a[11] ^= bw[11]
+		d.a[12] ^= bw[12]
+	}
+	if n >= 136 {
+		d.a[13] ^= bw[13]
+		d.a[14] ^= bw[14]
+		d.a[15] ^= bw[15]
+		d.a[16] ^= bw[16]
+	}
+	if n >= 144 {
+		d.a[17] ^= bw[17]
+	}
+	if n >= 168 {
+		d.a[18] ^= bw[18]
+		d.a[19] ^= bw[19]
+		d.a[20] ^= bw[20]
+	}
+}
+
+func copyOutUnaligned(d *state, buf []byte) {
+	ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0]))
+	copy(buf, ab[:])
+}
+
+var (
+	xorIn   = xorInUnaligned
+	copyOut = copyOutUnaligned
+)
+
+const xorImplementationUnaligned = "unaligned"
diff --git a/go/src/golang.org/x/crypto/ssh/agent/client.go b/go/src/golang.org/x/crypto/ssh/agent/client.go
index 1a91696..f5527e8 100644
--- a/go/src/golang.org/x/crypto/ssh/agent/client.go
+++ b/go/src/golang.org/x/crypto/ssh/agent/client.go
@@ -6,7 +6,7 @@
   Package agent implements a client to an ssh-agent daemon.
 
 References:
-  [PROTOCOL.agent]:    http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent
+  [PROTOCOL.agent]:    http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
 */
 package agent // import "golang.org/x/crypto/ssh/agent"
 
@@ -36,7 +36,7 @@
 	// in [PROTOCOL.agent] section 2.6.2.
 	Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
 
-	// Insert adds a private key to the agent. If a certificate
+	// Add adds a private key to the agent. If a certificate
 	// is given, that certificate is added as public key.
 	Add(s interface{}, cert *ssh.Certificate, comment string) error
 
diff --git a/go/src/golang.org/x/crypto/ssh/agent/keyring.go b/go/src/golang.org/x/crypto/ssh/agent/keyring.go
index 831a5b9..8ac2009 100644
--- a/go/src/golang.org/x/crypto/ssh/agent/keyring.go
+++ b/go/src/golang.org/x/crypto/ssh/agent/keyring.go
@@ -175,7 +175,7 @@
 		return nil, errLocked
 	}
 
-	s := make([]ssh.Signer, len(r.keys))
+	s := make([]ssh.Signer, 0, len(r.keys))
 	for _, k := range r.keys {
 		s = append(s, k.signer)
 	}
diff --git a/go/src/golang.org/x/crypto/ssh/certs.go b/go/src/golang.org/x/crypto/ssh/certs.go
index 9962ff0..3857700 100644
--- a/go/src/golang.org/x/crypto/ssh/certs.go
+++ b/go/src/golang.org/x/crypto/ssh/certs.go
@@ -85,46 +85,73 @@
 	return to
 }
 
+type optionsTuple struct {
+	Key   string
+	Value []byte
+}
+
+type optionsTupleValue struct {
+	Value string
+}
+
+// serialize a map of critical options or extensions
+// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
+// we need two length prefixes for a non-empty string value
 func marshalTuples(tups map[string]string) []byte {
 	keys := make([]string, 0, len(tups))
-	for k := range tups {
-		keys = append(keys, k)
+	for key := range tups {
+		keys = append(keys, key)
 	}
 	sort.Strings(keys)
 
-	var r []byte
-	for _, k := range keys {
-		s := struct{ K, V string }{k, tups[k]}
-		r = append(r, Marshal(&s)...)
+	var ret []byte
+	for _, key := range keys {
+		s := optionsTuple{Key: key}
+		if value := tups[key]; len(value) > 0 {
+			s.Value = Marshal(&optionsTupleValue{value})
+		}
+		ret = append(ret, Marshal(&s)...)
 	}
-	return r
+	return ret
 }
 
+// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
+// we need two length prefixes for a non-empty option value
 func parseTuples(in []byte) (map[string]string, error) {
 	tups := map[string]string{}
 	var lastKey string
 	var haveLastKey bool
 
 	for len(in) > 0 {
-		nameBytes, rest, ok := parseString(in)
-		if !ok {
-			return nil, errShortRead
-		}
-		data, rest, ok := parseString(rest)
-		if !ok {
-			return nil, errShortRead
-		}
-		name := string(nameBytes)
+		var key, val, extra []byte
+		var ok bool
 
+		if key, in, ok = parseString(in); !ok {
+			return nil, errShortRead
+		}
+		keyStr := string(key)
 		// according to [PROTOCOL.certkeys], the names must be in
 		// lexical order.
-		if haveLastKey && name <= lastKey {
+		if haveLastKey && keyStr <= lastKey {
 			return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
 		}
-		lastKey, haveLastKey = name, true
-
-		tups[name] = string(data)
-		in = rest
+		lastKey, haveLastKey = keyStr, true
+		// the next field is a data field, which if non-empty has a string embedded
+		if val, in, ok = parseString(in); !ok {
+			return nil, errShortRead
+		}
+		if len(val) > 0 {
+			val, extra, ok = parseString(val)
+			if !ok {
+				return nil, errShortRead
+			}
+			if len(extra) > 0 {
+				return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
+			}
+			tups[keyStr] = string(val)
+		} else {
+			tups[keyStr] = ""
+		}
 	}
 	return tups, nil
 }
@@ -341,7 +368,7 @@
 	if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
 		return fmt.Errorf("ssh: cert is not yet valid")
 	}
-	if before := int64(cert.ValidBefore); cert.ValidBefore != CertTimeInfinity && (unixNow >= before || before < 0) {
+	if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
 		return fmt.Errorf("ssh: cert has expired")
 	}
 	if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
diff --git a/go/src/golang.org/x/crypto/ssh/certs_test.go b/go/src/golang.org/x/crypto/ssh/certs_test.go
index 7d1b00f..d6c4a33 100644
--- a/go/src/golang.org/x/crypto/ssh/certs_test.go
+++ b/go/src/golang.org/x/crypto/ssh/certs_test.go
@@ -7,13 +7,14 @@
 import (
 	"bytes"
 	"crypto/rand"
+	"reflect"
 	"testing"
 	"time"
 )
 
 // Cert generated by ssh-keygen 6.0p1 Debian-4.
 // % ssh-keygen -s ca-key -I test user-key
-var exampleSSHCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8=`
+const exampleSSHCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8=`
 
 func TestParseCert(t *testing.T) {
 	authKeyBytes := []byte(exampleSSHCert)
@@ -27,7 +28,7 @@
 	}
 
 	if _, ok := key.(*Certificate); !ok {
-		t.Fatalf("got %#v, want *Certificate", key)
+		t.Fatalf("got %v (%T), want *Certificate", key, key)
 	}
 
 	marshaled := MarshalAuthorizedKey(key)
@@ -39,6 +40,60 @@
 	}
 }
 
+// Cert generated by ssh-keygen OpenSSH_6.8p1 OS X 10.10.3
+// % ssh-keygen -s ca -I testcert -O source-address=192.168.1.0/24 -O force-command=/bin/sleep user.pub
+// user.pub key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDACh1rt2DXfV3hk6fszSQcQ/rueMId0kVD9U7nl8cfEnFxqOCrNT92g4laQIGl2mn8lsGZfTLg8ksHq3gkvgO3oo/0wHy4v32JeBOHTsN5AL4gfHNEhWeWb50ev47hnTsRIt9P4dxogeUo/hTu7j9+s9lLpEQXCvq6xocXQt0j8MV9qZBBXFLXVT3cWIkSqOdwt/5ZBg+1GSrc7WfCXVWgTk4a20uPMuJPxU4RQwZW6X3+O8Pqo8C3cW0OzZRFP6gUYUKUsTI5WntlS+LAxgw1mZNsozFGdbiOPRnEryE3SRldh9vjDR3tin1fGpA5P7+CEB/bqaXtG3V+F2OkqaMN
+// Critical Options:
+//         force-command /bin/sleep
+//         source-address 192.168.1.0/24
+// Extensions:
+//         permit-X11-forwarding
+//         permit-agent-forwarding
+//         permit-port-forwarding
+//         permit-pty
+//         permit-user-rc
+const exampleSSHCertWithOptions = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgDyysCJY0XrO1n03EeRRoITnTPdjENFmWDs9X58PP3VUAAAADAQABAAABAQDACh1rt2DXfV3hk6fszSQcQ/rueMId0kVD9U7nl8cfEnFxqOCrNT92g4laQIGl2mn8lsGZfTLg8ksHq3gkvgO3oo/0wHy4v32JeBOHTsN5AL4gfHNEhWeWb50ev47hnTsRIt9P4dxogeUo/hTu7j9+s9lLpEQXCvq6xocXQt0j8MV9qZBBXFLXVT3cWIkSqOdwt/5ZBg+1GSrc7WfCXVWgTk4a20uPMuJPxU4RQwZW6X3+O8Pqo8C3cW0OzZRFP6gUYUKUsTI5WntlS+LAxgw1mZNsozFGdbiOPRnEryE3SRldh9vjDR3tin1fGpA5P7+CEB/bqaXtG3V+F2OkqaMNAAAAAAAAAAAAAAABAAAACHRlc3RjZXJ0AAAAAAAAAAAAAAAA//////////8AAABLAAAADWZvcmNlLWNvbW1hbmQAAAAOAAAACi9iaW4vc2xlZXAAAAAOc291cmNlLWFkZHJlc3MAAAASAAAADjE5Mi4xNjguMS4wLzI0AAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAwU+c5ui5A8+J/CFpjW8wCa52bEODA808WWQDCSuTG/eMXNf59v9Y8Pk0F1E9dGCosSNyVcB/hacUrc6He+i97+HJCyKavBsE6GDxrjRyxYqAlfcOXi/IVmaUGiO8OQ39d4GHrjToInKvExSUeleQyH4Y4/e27T/pILAqPFL3fyrvMLT5qU9QyIt6zIpa7GBP5+urouNavMprV3zsfIqNBbWypinOQAw823a5wN+zwXnhZrgQiHZ/USG09Y6k98y1dTVz8YHlQVR4D3lpTAsKDKJ5hCH9WU4fdf+lU8OyNGaJ/vz0XNqxcToe1l4numLTnaoSuH89pHryjqurB7lJKwAAAQ8AAAAHc3NoLXJzYQAAAQCaHvUIoPL1zWUHIXLvu96/HU1s/i4CAW2IIEuGgxCUCiFj6vyTyYtgxQxcmbfZf6eaITlS6XJZa7Qq4iaFZh75C1DXTX8labXhRSD4E2t//AIP9MC1rtQC5xo6FmbQ+BoKcDskr+mNACcbRSxs3IL3bwCfWDnIw2WbVox9ZdcthJKk4UoCW4ix4QwdHw7zlddlz++fGEEVhmTbll1SUkycGApPFBsAYRTMupUJcYPIeReBI/m8XfkoMk99bV8ZJQTAd7OekHY2/48Ff53jLmyDjP7kNw1F8OaPtkFs6dGJXta4krmaekPy87j+35In5hFj7yoOqvSbmYUkeX70/GGQ`
+
+func TestParseCertWithOptions(t *testing.T) {
+	opts := map[string]string{
+		"source-address": "192.168.1.0/24",
+		"force-command":  "/bin/sleep",
+	}
+	exts := map[string]string{
+		"permit-X11-forwarding":   "",
+		"permit-agent-forwarding": "",
+		"permit-port-forwarding":  "",
+		"permit-pty":              "",
+		"permit-user-rc":          "",
+	}
+	authKeyBytes := []byte(exampleSSHCertWithOptions)
+
+	key, _, _, rest, err := ParseAuthorizedKey(authKeyBytes)
+	if err != nil {
+		t.Fatalf("ParseAuthorizedKey: %v", err)
+	}
+	if len(rest) > 0 {
+		t.Errorf("rest: got %q, want empty", rest)
+	}
+	cert, ok := key.(*Certificate)
+	if !ok {
+		t.Fatalf("got %v (%T), want *Certificate", key, key)
+	}
+	if !reflect.DeepEqual(cert.CriticalOptions, opts) {
+		t.Errorf("unexpected critical options - got %v, want %v", cert.CriticalOptions, opts)
+	}
+	if !reflect.DeepEqual(cert.Extensions, exts) {
+		t.Errorf("unexpected Extensions - got %v, want %v", cert.Extensions, exts)
+	}
+	marshaled := MarshalAuthorizedKey(key)
+	// Before comparison, remove the trailing newline that
+	// MarshalAuthorizedKey adds.
+	marshaled = marshaled[:len(marshaled)-1]
+	if !bytes.Equal(authKeyBytes, marshaled) {
+		t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, authKeyBytes)
+	}
+}
+
 func TestValidateCert(t *testing.T) {
 	key, _, _, _, err := ParseAuthorizedKey([]byte(exampleSSHCert))
 	if err != nil {
diff --git a/go/src/golang.org/x/crypto/ssh/cipher.go b/go/src/golang.org/x/crypto/ssh/cipher.go
index 642696b..3e06da0 100644
--- a/go/src/golang.org/x/crypto/ssh/cipher.go
+++ b/go/src/golang.org/x/crypto/ssh/cipher.go
@@ -14,6 +14,7 @@
 	"fmt"
 	"hash"
 	"io"
+	"io/ioutil"
 )
 
 const (
@@ -113,6 +114,10 @@
 	// special case. If we add any more non-stream ciphers, we
 	// should invest a cleaner way to do this.
 	gcmCipherID: {16, 12, 0, nil},
+
+	// insecure cipher, see http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf
+	// uncomment below to enable it.
+	// aes128cbcID: {16, aes.BlockSize, 0, nil},
 }
 
 // prefixLen is the length of the packet prefix that contains the packet length
@@ -342,3 +347,203 @@
 	plain = plain[1 : length-uint32(padding)]
 	return plain, nil
 }
+
+// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
+type cbcCipher struct {
+	mac       hash.Hash
+	macSize   uint32
+	decrypter cipher.BlockMode
+	encrypter cipher.BlockMode
+
+	// The following members are to avoid per-packet allocations.
+	seqNumBytes [4]byte
+	packetData  []byte
+	macResult   []byte
+
+	// Amount of data we should still read to hide which
+	// verification error triggered.
+	oracleCamouflage uint32
+}
+
+func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+	c, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	cbc := &cbcCipher{
+		mac:        macModes[algs.MAC].new(macKey),
+		decrypter:  cipher.NewCBCDecrypter(c, iv),
+		encrypter:  cipher.NewCBCEncrypter(c, iv),
+		packetData: make([]byte, 1024),
+	}
+	if cbc.mac != nil {
+		cbc.macSize = uint32(cbc.mac.Size())
+	}
+
+	return cbc, nil
+}
+
+func maxUInt32(a, b int) uint32 {
+	if a > b {
+		return uint32(a)
+	}
+	return uint32(b)
+}
+
+const (
+	cbcMinPacketSizeMultiple = 8
+	cbcMinPacketSize         = 16
+	cbcMinPaddingSize        = 4
+)
+
+// cbcError represents a verification error that may leak information.
+type cbcError string
+
+func (e cbcError) Error() string { return string(e) }
+
+func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+	p, err := c.readPacketLeaky(seqNum, r)
+	if err != nil {
+		if _, ok := err.(cbcError); ok {
+			// Verification error: read a fixed amount of
+			// data, to make distinguishing between
+			// failing MAC and failing length check more
+			// difficult.
+			io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage))
+		}
+	}
+	return p, err
+}
+
+func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
+	blockSize := c.decrypter.BlockSize()
+
+	// Read the header, which will include some of the subsequent data in the
+	// case of block ciphers - this is copied back to the payload later.
+	// How many bytes of payload/padding will be read with this first read.
+	firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
+	firstBlock := c.packetData[:firstBlockLength]
+	if _, err := io.ReadFull(r, firstBlock); err != nil {
+		return nil, err
+	}
+
+	c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
+
+	c.decrypter.CryptBlocks(firstBlock, firstBlock)
+	length := binary.BigEndian.Uint32(firstBlock[:4])
+	if length > maxPacket {
+		return nil, cbcError("ssh: packet too large")
+	}
+	if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
+		// The minimum size of a packet is 16 (or the cipher block size, whichever
+		// is larger) bytes.
+		return nil, cbcError("ssh: packet too small")
+	}
+	// The length of the packet (including the length field but not the MAC) must
+	// be a multiple of the block size or 8, whichever is larger.
+	if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
+		return nil, cbcError("ssh: invalid packet length multiple")
+	}
+
+	paddingLength := uint32(firstBlock[4])
+	if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
+		return nil, cbcError("ssh: invalid packet length")
+	}
+
+	// Positions within the c.packetData buffer:
+	macStart := 4 + length
+	paddingStart := macStart - paddingLength
+
+	// Entire packet size, starting before length, ending at end of mac.
+	entirePacketSize := macStart + c.macSize
+
+	// Ensure c.packetData is large enough for the entire packet data.
+	if uint32(cap(c.packetData)) < entirePacketSize {
+		// Still need to upsize and copy, but this should be rare at runtime, only
+		// on upsizing the packetData buffer.
+		c.packetData = make([]byte, entirePacketSize)
+		copy(c.packetData, firstBlock)
+	} else {
+		c.packetData = c.packetData[:entirePacketSize]
+	}
+
+	if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil {
+		return nil, err
+	} else {
+		c.oracleCamouflage -= uint32(n)
+	}
+
+	remainingCrypted := c.packetData[firstBlockLength:macStart]
+	c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
+
+	mac := c.packetData[macStart:]
+	if c.mac != nil {
+		c.mac.Reset()
+		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
+		c.mac.Write(c.seqNumBytes[:])
+		c.mac.Write(c.packetData[:macStart])
+		c.macResult = c.mac.Sum(c.macResult[:0])
+		if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
+			return nil, cbcError("ssh: MAC failure")
+		}
+	}
+
+	return c.packetData[prefixLen:paddingStart], nil
+}
+
+func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+	effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
+
+	// Length of encrypted portion of the packet (header, payload, padding).
+	// Enforce minimum padding and packet size.
+	encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
+	// Enforce block size.
+	encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
+
+	length := encLength - 4
+	paddingLength := int(length) - (1 + len(packet))
+
+	// Overall buffer contains: header, payload, padding, mac.
+	// Space for the MAC is reserved in the capacity but not the slice length.
+	bufferSize := encLength + c.macSize
+	if uint32(cap(c.packetData)) < bufferSize {
+		c.packetData = make([]byte, encLength, bufferSize)
+	} else {
+		c.packetData = c.packetData[:encLength]
+	}
+
+	p := c.packetData
+
+	// Packet header.
+	binary.BigEndian.PutUint32(p, length)
+	p = p[4:]
+	p[0] = byte(paddingLength)
+
+	// Payload.
+	p = p[1:]
+	copy(p, packet)
+
+	// Padding.
+	p = p[len(packet):]
+	if _, err := io.ReadFull(rand, p); err != nil {
+		return err
+	}
+
+	if c.mac != nil {
+		c.mac.Reset()
+		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
+		c.mac.Write(c.seqNumBytes[:])
+		c.mac.Write(c.packetData)
+		// The MAC is now appended into the capacity reserved for it earlier.
+		c.packetData = c.mac.Sum(c.packetData)
+	}
+
+	c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
+
+	if _, err := w.Write(c.packetData); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/go/src/golang.org/x/crypto/ssh/cipher_test.go b/go/src/golang.org/x/crypto/ssh/cipher_test.go
index e279af0..54b92b6 100644
--- a/go/src/golang.org/x/crypto/ssh/cipher_test.go
+++ b/go/src/golang.org/x/crypto/ssh/cipher_test.go
@@ -7,6 +7,7 @@
 import (
 	"bytes"
 	"crypto"
+	"crypto/aes"
 	"crypto/rand"
 	"testing"
 )
@@ -20,6 +21,10 @@
 }
 
 func TestPacketCiphers(t *testing.T) {
+	// Still test aes128cbc cipher althought it's commented out.
+	cipherModes[aes128cbcID] = &streamCipherMode{16, aes.BlockSize, 0, nil}
+	defer delete(cipherModes, aes128cbcID)
+
 	for cipher := range cipherModes {
 		kr := &kexResult{Hash: crypto.SHA1}
 		algs := directionAlgorithms{
@@ -57,3 +62,66 @@
 		}
 	}
 }
+
+func TestCBCOracleCounterMeasure(t *testing.T) {
+	cipherModes[aes128cbcID] = &streamCipherMode{16, aes.BlockSize, 0, nil}
+	defer delete(cipherModes, aes128cbcID)
+
+	kr := &kexResult{Hash: crypto.SHA1}
+	algs := directionAlgorithms{
+		Cipher:      aes128cbcID,
+		MAC:         "hmac-sha1",
+		Compression: "none",
+	}
+	client, err := newPacketCipher(clientKeys, algs, kr)
+	if err != nil {
+		t.Fatalf("newPacketCipher(client): %v", err)
+	}
+
+	want := "bla bla"
+	input := []byte(want)
+	buf := &bytes.Buffer{}
+	if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
+		t.Errorf("writePacket: %v", err)
+	}
+
+	packetSize := buf.Len()
+	buf.Write(make([]byte, 2*maxPacket))
+
+	// We corrupt each byte, but this usually will only test the
+	// 'packet too large' or 'MAC failure' cases.
+	lastRead := -1
+	for i := 0; i < packetSize; i++ {
+		server, err := newPacketCipher(clientKeys, algs, kr)
+		if err != nil {
+			t.Fatalf("newPacketCipher(client): %v", err)
+		}
+
+		fresh := &bytes.Buffer{}
+		fresh.Write(buf.Bytes())
+		fresh.Bytes()[i] ^= 0x01
+
+		before := fresh.Len()
+		_, err = server.readPacket(0, fresh)
+		if err == nil {
+			t.Errorf("corrupt byte %d: readPacket succeeded ", i)
+			continue
+		}
+		if _, ok := err.(cbcError); !ok {
+			t.Errorf("corrupt byte %d: got %v (%T), want cbcError", i, err, err)
+			continue
+		}
+
+		after := fresh.Len()
+		bytesRead := before - after
+		if bytesRead < maxPacket {
+			t.Errorf("corrupt byte %d: read %d bytes, want more than %d", i, bytesRead, maxPacket)
+			continue
+		}
+
+		if i > 0 && bytesRead != lastRead {
+			t.Errorf("corrupt byte %d: read %d bytes, want %d bytes read", i, bytesRead, lastRead)
+		}
+		lastRead = bytesRead
+	}
+}
diff --git a/go/src/golang.org/x/crypto/ssh/client.go b/go/src/golang.org/x/crypto/ssh/client.go
index 03c4e77..72bd27f 100644
--- a/go/src/golang.org/x/crypto/ssh/client.go
+++ b/go/src/golang.org/x/crypto/ssh/client.go
@@ -82,11 +82,11 @@
 // clientHandshake performs the client side key exchange. See RFC 4253 Section
 // 7.
 func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error {
-	c.clientVersion = []byte(packageVersion)
 	if config.ClientVersion != "" {
 		c.clientVersion = []byte(config.ClientVersion)
+	} else {
+		c.clientVersion = []byte(packageVersion)
 	}
-
 	var err error
 	c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
 	if err != nil {
@@ -105,6 +105,10 @@
 	} else if packet[0] != msgNewKeys {
 		return unexpectedMessageError(msgNewKeys, packet[0])
 	}
+
+	// We just did the key change, so the session ID is established.
+	c.sessionID = c.transport.getSessionID()
+
 	return c.clientAuthenticate(config)
 }
 
diff --git a/go/src/golang.org/x/crypto/ssh/common.go b/go/src/golang.org/x/crypto/ssh/common.go
index 2fd7fd9..0a9df1f 100644
--- a/go/src/golang.org/x/crypto/ssh/common.go
+++ b/go/src/golang.org/x/crypto/ssh/common.go
@@ -53,7 +53,7 @@
 // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
 // because they have reached the end of their useful life.
 var supportedMACs = []string{
-	"hmac-sha1", "hmac-sha1-96",
+	"hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
 }
 
 var supportedCompressions = []string{compressionNone}
@@ -206,6 +206,14 @@
 	if c.Ciphers == nil {
 		c.Ciphers = supportedCiphers
 	}
+	var ciphers []string
+	for _, c := range c.Ciphers {
+		if cipherModes[c] != nil {
+			// reject the cipher if we have no cipherModes definition
+			ciphers = append(ciphers, c)
+		}
+	}
+	c.Ciphers = ciphers
 
 	if c.KeyExchanges == nil {
 		c.KeyExchanges = supportedKexAlgos
diff --git a/go/src/golang.org/x/crypto/ssh/connection.go b/go/src/golang.org/x/crypto/ssh/connection.go
index 93551e2..979d919 100644
--- a/go/src/golang.org/x/crypto/ssh/connection.go
+++ b/go/src/golang.org/x/crypto/ssh/connection.go
@@ -33,7 +33,7 @@
 	// into the session ID.
 	ClientVersion() []byte
 
-	// ServerVersion returns the client's version string as hashed
+	// ServerVersion returns the server's version string as hashed
 	// into the session ID.
 	ServerVersion() []byte
 
diff --git a/go/src/golang.org/x/crypto/ssh/doc.go b/go/src/golang.org/x/crypto/ssh/doc.go
index fb6402b..d6be894 100644
--- a/go/src/golang.org/x/crypto/ssh/doc.go
+++ b/go/src/golang.org/x/crypto/ssh/doc.go
@@ -12,7 +12,7 @@
 others.
 
 References:
-  [PROTOCOL.certkeys]: http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys
+  [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
   [SSH-PARAMETERS]:    http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
 */
 package ssh // import "golang.org/x/crypto/ssh"
diff --git a/go/src/golang.org/x/crypto/ssh/example_test.go b/go/src/golang.org/x/crypto/ssh/example_test.go
index 22f42ec..dfd9dca 100644
--- a/go/src/golang.org/x/crypto/ssh/example_test.go
+++ b/go/src/golang.org/x/crypto/ssh/example_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package ssh
+package ssh_test
 
 import (
 	"bytes"
@@ -12,14 +12,15 @@
 	"net"
 	"net/http"
 
+	"golang.org/x/crypto/ssh"
 	"golang.org/x/crypto/ssh/terminal"
 )
 
 func ExampleNewServerConn() {
 	// An SSH server is represented by a ServerConfig, which holds
 	// certificate details and handles authentication of ServerConns.
-	config := &ServerConfig{
-		PasswordCallback: func(c ConnMetadata, pass []byte) (*Permissions, error) {
+	config := &ssh.ServerConfig{
+		PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
 			// Should use constant-time compare (or better, salt+hash) in
 			// a production setting.
 			if c.User() == "testuser" && string(pass) == "tiger" {
@@ -34,7 +35,7 @@
 		panic("Failed to load private key")
 	}
 
-	private, err := ParsePrivateKey(privateBytes)
+	private, err := ssh.ParsePrivateKey(privateBytes)
 	if err != nil {
 		panic("Failed to parse private key")
 	}
@@ -54,12 +55,12 @@
 
 	// Before use, a handshake must be performed on the incoming
 	// net.Conn.
-	_, chans, reqs, err := NewServerConn(nConn, config)
+	_, chans, reqs, err := ssh.NewServerConn(nConn, config)
 	if err != nil {
 		panic("failed to handshake")
 	}
 	// The incoming Request channel must be serviced.
-	go DiscardRequests(reqs)
+	go ssh.DiscardRequests(reqs)
 
 	// Service the incoming Channel channel.
 	for newChannel := range chans {
@@ -68,7 +69,7 @@
 		// "session" and ServerShell may be used to present a simple
 		// terminal interface.
 		if newChannel.ChannelType() != "session" {
-			newChannel.Reject(UnknownChannelType, "unknown channel type")
+			newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
 			continue
 		}
 		channel, requests, err := newChannel.Accept()
@@ -79,7 +80,7 @@
 		// Sessions have out-of-band requests such as "shell",
 		// "pty-req" and "env".  Here we handle only the
 		// "shell" request.
-		go func(in <-chan *Request) {
+		go func(in <-chan *ssh.Request) {
 			for req := range in {
 				ok := false
 				switch req.Type {
@@ -117,13 +118,13 @@
 	//
 	// To authenticate with the remote server you must pass at least one
 	// implementation of AuthMethod via the Auth field in ClientConfig.
-	config := &ClientConfig{
+	config := &ssh.ClientConfig{
 		User: "username",
-		Auth: []AuthMethod{
-			Password("yourpassword"),
+		Auth: []ssh.AuthMethod{
+			ssh.Password("yourpassword"),
 		},
 	}
-	client, err := Dial("tcp", "yourserver.com:22", config)
+	client, err := ssh.Dial("tcp", "yourserver.com:22", config)
 	if err != nil {
 		panic("Failed to dial: " + err.Error())
 	}
@@ -147,14 +148,14 @@
 }
 
 func ExampleClient_Listen() {
-	config := &ClientConfig{
+	config := &ssh.ClientConfig{
 		User: "username",
-		Auth: []AuthMethod{
-			Password("password"),
+		Auth: []ssh.AuthMethod{
+			ssh.Password("password"),
 		},
 	}
 	// Dial your ssh server.
-	conn, err := Dial("tcp", "localhost:22", config)
+	conn, err := ssh.Dial("tcp", "localhost:22", config)
 	if err != nil {
 		log.Fatalf("unable to connect: %s", err)
 	}
@@ -175,14 +176,14 @@
 
 func ExampleSession_RequestPty() {
 	// Create client config
-	config := &ClientConfig{
+	config := &ssh.ClientConfig{
 		User: "username",
-		Auth: []AuthMethod{
-			Password("password"),
+		Auth: []ssh.AuthMethod{
+			ssh.Password("password"),
 		},
 	}
 	// Connect to ssh server
-	conn, err := Dial("tcp", "localhost:22", config)
+	conn, err := ssh.Dial("tcp", "localhost:22", config)
 	if err != nil {
 		log.Fatalf("unable to connect: %s", err)
 	}
@@ -194,10 +195,10 @@
 	}
 	defer session.Close()
 	// Set up terminal modes
-	modes := TerminalModes{
-		ECHO:          0,     // disable echoing
-		TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
-		TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
+	modes := ssh.TerminalModes{
+		ssh.ECHO:          0,     // disable echoing
+		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
+		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
 	}
 	// Request pseudo terminal
 	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
diff --git a/go/src/golang.org/x/crypto/ssh/mac.go b/go/src/golang.org/x/crypto/ssh/mac.go
index aff4042..07744ad 100644
--- a/go/src/golang.org/x/crypto/ssh/mac.go
+++ b/go/src/golang.org/x/crypto/ssh/mac.go
@@ -9,6 +9,7 @@
 import (
 	"crypto/hmac"
 	"crypto/sha1"
+	"crypto/sha256"
 	"hash"
 )
 
@@ -44,6 +45,9 @@
 func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
 
 var macModes = map[string]*macMode{
+	"hmac-sha2-256": {32, func(key []byte) hash.Hash {
+		return hmac.New(sha256.New, key)
+	}},
 	"hmac-sha1": {20, func(key []byte) hash.Hash {
 		return hmac.New(sha1.New, key)
 	}},
diff --git a/go/src/golang.org/x/crypto/ssh/messages.go b/go/src/golang.org/x/crypto/ssh/messages.go
index f9e44bb..eaf6106 100644
--- a/go/src/golang.org/x/crypto/ssh/messages.go
+++ b/go/src/golang.org/x/crypto/ssh/messages.go
@@ -484,11 +484,12 @@
 		return
 	}
 	length := binary.BigEndian.Uint32(in)
-	if uint32(len(in)) < 4+length {
+	in = in[4:]
+	if uint32(len(in)) < length {
 		return
 	}
-	out = in[4 : 4+length]
-	rest = in[4+length:]
+	out = in[:length]
+	rest = in[length:]
 	ok = true
 	return
 }
diff --git a/go/src/golang.org/x/crypto/ssh/messages_test.go b/go/src/golang.org/x/crypto/ssh/messages_test.go
index 21d52da..955b512 100644
--- a/go/src/golang.org/x/crypto/ssh/messages_test.go
+++ b/go/src/golang.org/x/crypto/ssh/messages_test.go
@@ -162,6 +162,16 @@
 	}
 }
 
+func TestUnmarshalShortKexInitPacket(t *testing.T) {
+	// This used to panic.
+	// Issue 11348
+	packet := []byte{0x14, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xff, 0xff, 0xff}
+	kim := &kexInitMsg{}
+	if err := Unmarshal(packet, kim); err == nil {
+		t.Error("truncated packet unmarshaled without error")
+	}
+}
+
 func randomBytes(out []byte, rand *rand.Rand) {
 	for i := 0; i < len(out); i++ {
 		out[i] = byte(rand.Int31())
diff --git a/go/src/golang.org/x/crypto/ssh/server.go b/go/src/golang.org/x/crypto/ssh/server.go
index 8c4f142..baedf5b 100644
--- a/go/src/golang.org/x/crypto/ssh/server.go
+++ b/go/src/golang.org/x/crypto/ssh/server.go
@@ -65,6 +65,11 @@
 	// AuthLogCallback, if non-nil, is called to log all authentication
 	// attempts.
 	AuthLogCallback func(conn ConnMetadata, method string, err error)
+
+	// ServerVersion is the version identification string to
+	// announce in the public handshake.
+	// If empty, a reasonable default is used.
+	ServerVersion string
 }
 
 // AddHostKey adds a private key as a host key. If an existing host
@@ -163,8 +168,16 @@
 		return nil, errors.New("ssh: server has no host keys")
 	}
 
+	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil {
+		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
+	}
+
+	if config.ServerVersion != "" {
+		s.serverVersion = []byte(config.ServerVersion)
+	} else {
+		s.serverVersion = []byte(packageVersion)
+	}
 	var err error
-	s.serverVersion = []byte(packageVersion)
 	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
 	if err != nil {
 		return nil, err
@@ -183,6 +196,9 @@
 		return nil, unexpectedMessageError(msgNewKeys, packet[0])
 	}
 
+	// We just did the key change, so the session ID is established.
+	s.sessionID = s.transport.getSessionID()
+
 	var packet []byte
 	if packet, err = s.transport.readPacket(); err != nil {
 		return nil, err
diff --git a/go/src/golang.org/x/crypto/ssh/session_test.go b/go/src/golang.org/x/crypto/ssh/session_test.go
index fce9868..7ce44f5 100644
--- a/go/src/golang.org/x/crypto/ssh/session_test.go
+++ b/go/src/golang.org/x/crypto/ssh/session_test.go
@@ -9,9 +9,11 @@
 import (
 	"bytes"
 	crypto_rand "crypto/rand"
+	"errors"
 	"io"
 	"io/ioutil"
 	"math/rand"
+	"net"
 	"testing"
 
 	"golang.org/x/crypto/ssh/terminal"
@@ -626,3 +628,93 @@
 		t.Errorf("handler write error: %v", err)
 	}
 }
+
+func TestSessionID(t *testing.T) {
+	c1, c2, err := netPipe()
+	if err != nil {
+		t.Fatalf("netPipe: %v", err)
+	}
+	defer c1.Close()
+	defer c2.Close()
+
+	serverID := make(chan []byte, 1)
+	clientID := make(chan []byte, 1)
+
+	serverConf := &ServerConfig{
+		NoClientAuth: true,
+	}
+	serverConf.AddHostKey(testSigners["ecdsa"])
+	clientConf := &ClientConfig{
+		User: "user",
+	}
+
+	go func() {
+		conn, chans, reqs, err := NewServerConn(c1, serverConf)
+		if err != nil {
+			t.Fatalf("server handshake: %v", err)
+		}
+		serverID <- conn.SessionID()
+		go DiscardRequests(reqs)
+		for ch := range chans {
+			ch.Reject(Prohibited, "")
+		}
+	}()
+
+	go func() {
+		conn, chans, reqs, err := NewClientConn(c2, "", clientConf)
+		if err != nil {
+			t.Fatalf("client handshake: %v", err)
+		}
+		clientID <- conn.SessionID()
+		go DiscardRequests(reqs)
+		for ch := range chans {
+			ch.Reject(Prohibited, "")
+		}
+	}()
+
+	s := <-serverID
+	c := <-clientID
+	if bytes.Compare(s, c) != 0 {
+		t.Errorf("server session ID (%x) != client session ID (%x)", s, c)
+	} else if len(s) == 0 {
+		t.Errorf("client and server SessionID were empty.")
+	}
+}
+
+type noReadConn struct {
+	readSeen bool
+	net.Conn
+}
+
+func (c *noReadConn) Close() error {
+	return nil
+}
+
+func (c *noReadConn) Read(b []byte) (int, error) {
+	c.readSeen = true
+	return 0, errors.New("noReadConn error")
+}
+
+func TestInvalidServerConfiguration(t *testing.T) {
+	c1, c2, err := netPipe()
+	if err != nil {
+		t.Fatalf("netPipe: %v", err)
+	}
+	defer c1.Close()
+	defer c2.Close()
+
+	serveConn := noReadConn{Conn: c1}
+	serverConf := &ServerConfig{}
+
+	NewServerConn(&serveConn, serverConf)
+	if serveConn.readSeen {
+		t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing host key")
+	}
+
+	serverConf.AddHostKey(testSigners["ecdsa"])
+
+	NewServerConn(&serveConn, serverConf)
+	if serveConn.readSeen {
+		t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing authentication method")
+	}
+}
diff --git a/go/src/golang.org/x/crypto/ssh/terminal/terminal.go b/go/src/golang.org/x/crypto/ssh/terminal/terminal.go
index 965f0cf..741eeb1 100644
--- a/go/src/golang.org/x/crypto/ssh/terminal/terminal.go
+++ b/go/src/golang.org/x/crypto/ssh/terminal/terminal.go
@@ -789,6 +789,10 @@
 		// If the width didn't change then nothing else needs to be
 		// done.
 		return nil
+	case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
+		// If there is nothing on current line and no prompt printed,
+		// just do nothing
+		return nil
 	case width < oldWidth:
 		// Some terminals (e.g. xterm) will truncate lines that were
 		// too long when shinking. Others, (e.g. gnome-terminal) will
diff --git a/go/src/golang.org/x/crypto/ssh/terminal/terminal_test.go b/go/src/golang.org/x/crypto/ssh/terminal/terminal_test.go
index 6579801..a663fe4 100644
--- a/go/src/golang.org/x/crypto/ssh/terminal/terminal_test.go
+++ b/go/src/golang.org/x/crypto/ssh/terminal/terminal_test.go
@@ -241,3 +241,29 @@
 		t.Fatalf("password was saved in history")
 	}
 }
+
+var setSizeTests = []struct {
+	width, height int
+}{
+	{40, 13},
+	{80, 24},
+	{132, 43},
+}
+
+func TestTerminalSetSize(t *testing.T) {
+	for _, setSize := range setSizeTests {
+		c := &MockTerminal{
+			toSend:       []byte("password\r\x1b[A\r"),
+			bytesPerRead: 1,
+		}
+		ss := NewTerminal(c, "> ")
+		ss.SetSize(setSize.width, setSize.height)
+		pw, _ := ss.ReadPassword("Password: ")
+		if pw != "password" {
+			t.Fatalf("failed to read password, got %s", pw)
+		}
+		if string(c.received) != "Password: \r\n" {
+			t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received)
+		}
+	}
+}
diff --git a/go/src/golang.org/x/crypto/ssh/test/doc.go b/go/src/golang.org/x/crypto/ssh/test/doc.go
index d21d6b7..3f9b334 100644
--- a/go/src/golang.org/x/crypto/ssh/test/doc.go
+++ b/go/src/golang.org/x/crypto/ssh/test/doc.go
@@ -3,5 +3,5 @@
 // license that can be found in the LICENSE file.
 
 // This package contains integration tests for the
-// code.google.com/p/go.crypto/ssh package.
+// golang.org/x/crypto/ssh package.
 package test // import "golang.org/x/crypto/ssh/test"
diff --git a/go/src/golang.org/x/crypto/ssh/test/session_test.go b/go/src/golang.org/x/crypto/ssh/test/session_test.go
index 0b7892b..fbd1044 100644
--- a/go/src/golang.org/x/crypto/ssh/test/session_test.go
+++ b/go/src/golang.org/x/crypto/ssh/test/session_test.go
@@ -11,10 +11,11 @@
 import (
 	"bytes"
 	"errors"
-	"golang.org/x/crypto/ssh"
 	"io"
 	"strings"
 	"testing"
+
+	"golang.org/x/crypto/ssh"
 )
 
 func TestRunCommandSuccess(t *testing.T) {
@@ -279,6 +280,9 @@
 	var config ssh.Config
 	config.SetDefaults()
 	cipherOrder := config.Ciphers
+	// This cipher will not be tested when commented out in cipher.go it will
+	// fallback to the next available as per line 292.
+	cipherOrder = append(cipherOrder, "aes128-cbc")
 
 	for _, ciph := range cipherOrder {
 		server := newServer(t)
diff --git a/go/src/golang.org/x/crypto/ssh/testdata/doc.go b/go/src/golang.org/x/crypto/ssh/testdata/doc.go
index 3f4d74d..fcae47c 100644
--- a/go/src/golang.org/x/crypto/ssh/testdata/doc.go
+++ b/go/src/golang.org/x/crypto/ssh/testdata/doc.go
@@ -3,6 +3,6 @@
 // license that can be found in the LICENSE file.
 
 // This package contains test data shared between the various subpackages of
-// the code.google.com/p/go.crypto/ssh package. Under no circumstance should
+// the golang.org/x/crypto/ssh package. Under no circumstance should
 // this data be used for production code.
 package testdata // import "golang.org/x/crypto/ssh/testdata"
diff --git a/go/src/golang.org/x/crypto/ssh/transport.go b/go/src/golang.org/x/crypto/ssh/transport.go
index 4f68b04..8351d37 100644
--- a/go/src/golang.org/x/crypto/ssh/transport.go
+++ b/go/src/golang.org/x/crypto/ssh/transport.go
@@ -12,6 +12,7 @@
 
 const (
 	gcmCipherID = "aes128-gcm@openssh.com"
+	aes128cbcID = "aes128-cbc"
 )
 
 // packetConn represents a transport that implements packet based
@@ -44,13 +45,13 @@
 	sessionID []byte
 }
 
+// getSessionID returns the ID of the SSH connection. The return value
+// should not be modified.
 func (t *transport) getSessionID() []byte {
 	if t.sessionID == nil {
 		panic("session ID not set yet")
 	}
-	s := make([]byte, len(t.sessionID))
-	copy(s, t.sessionID)
-	return s
+	return t.sessionID
 }
 
 // packetCipher represents a combination of SSH encryption/MAC
@@ -218,6 +219,10 @@
 		return newGCMCipher(iv, key, macKey)
 	}
 
+	if algs.Cipher == aes128cbcID {
+		return newAESCBCCipher(iv, key, macKey, algs)
+	}
+
 	c := &streamPacketCipher{
 		mac: macModes[algs.MAC].new(macKey),
 	}