Switch from Godep to go vendoring
This commit is contained in:
parent
6b37713bc0
commit
cd317761c5
1504 changed files with 263076 additions and 34441 deletions
673
vendor/golang.org/x/crypto/ocsp/ocsp.go
generated
vendored
Normal file
673
vendor/golang.org/x/crypto/ocsp/ocsp.go
generated
vendored
Normal file
|
@ -0,0 +1,673 @@
|
|||
// Copyright 2013 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 ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
|
||||
// are signed messages attesting to the validity of a certificate for a small
|
||||
// period of time. This is used to manage revocation for X.509 certificates.
|
||||
package ocsp // import "golang.org/x/crypto/ocsp"
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
|
||||
|
||||
// ResponseStatus contains the result of an OCSP request. See
|
||||
// https://tools.ietf.org/html/rfc6960#section-2.3
|
||||
type ResponseStatus int
|
||||
|
||||
const (
|
||||
Success ResponseStatus = 0
|
||||
Malformed ResponseStatus = 1
|
||||
InternalError ResponseStatus = 2
|
||||
TryLater ResponseStatus = 3
|
||||
// Status code four is ununsed in OCSP. See
|
||||
// https://tools.ietf.org/html/rfc6960#section-4.2.1
|
||||
SignatureRequired ResponseStatus = 5
|
||||
Unauthorized ResponseStatus = 6
|
||||
)
|
||||
|
||||
func (r ResponseStatus) String() string {
|
||||
switch r {
|
||||
case Success:
|
||||
return "success"
|
||||
case Malformed:
|
||||
return "malformed"
|
||||
case InternalError:
|
||||
return "internal error"
|
||||
case TryLater:
|
||||
return "try later"
|
||||
case SignatureRequired:
|
||||
return "signature required"
|
||||
case Unauthorized:
|
||||
return "unauthorized"
|
||||
default:
|
||||
return "unknown OCSP status: " + strconv.Itoa(int(r))
|
||||
}
|
||||
}
|
||||
|
||||
// ResponseError is an error that may be returned by ParseResponse to indicate
|
||||
// that the response itself is an error, not just that its indicating that a
|
||||
// certificate is revoked, unknown, etc.
|
||||
type ResponseError struct {
|
||||
Status ResponseStatus
|
||||
}
|
||||
|
||||
func (r ResponseError) Error() string {
|
||||
return "ocsp: error from server: " + r.Status.String()
|
||||
}
|
||||
|
||||
// These are internal structures that reflect the ASN.1 structure of an OCSP
|
||||
// response. See RFC 2560, section 4.2.
|
||||
|
||||
type certID struct {
|
||||
HashAlgorithm pkix.AlgorithmIdentifier
|
||||
NameHash []byte
|
||||
IssuerKeyHash []byte
|
||||
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,optional"`
|
||||
}
|
||||
|
||||
type responseBytes struct {
|
||||
ResponseType asn1.ObjectIdentifier
|
||||
Response []byte
|
||||
}
|
||||
|
||||
type basicResponse struct {
|
||||
TBSResponseData responseData
|
||||
SignatureAlgorithm pkix.AlgorithmIdentifier
|
||||
Signature asn1.BitString
|
||||
Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
|
||||
}
|
||||
|
||||
type responseData struct {
|
||||
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:"tag:0,optional"`
|
||||
Revoked revokedInfo `asn1:"tag:1,optional"`
|
||||
Unknown asn1.Flag `asn1:"tag:2,optional"`
|
||||
ThisUpdate time.Time `asn1:"generalized"`
|
||||
NextUpdate time.Time `asn1:"generalized,explicit,tag:0,optional"`
|
||||
SingleExtensions []pkix.Extension `asn1:"explicit,tag:1,optional"`
|
||||
}
|
||||
|
||||
type revokedInfo struct {
|
||||
RevocationTime time.Time `asn1:"generalized"`
|
||||
Reason asn1.Enumerated `asn1:"explicit,tag:0,optional"`
|
||||
}
|
||||
|
||||
var (
|
||||
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
|
||||
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
||||
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
||||
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
||||
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
|
||||
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
|
||||
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
||||
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2}
|
||||
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
||||
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
||||
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 {
|
||||
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.
|
||||
|
||||
// The status values that can be expressed in OCSP. See RFC 6960.
|
||||
const (
|
||||
// Good means that the certificate is valid.
|
||||
Good = iota
|
||||
// Revoked means that the certificate has been deliberately revoked.
|
||||
Revoked
|
||||
// Unknown means that the OCSP responder doesn't know about the certificate.
|
||||
Unknown
|
||||
// ServerFailed is unused and was never used (see
|
||||
// https://go-review.googlesource.com/#/c/18944). ParseResponse will
|
||||
// return a ResponseError when an error response is parsed.
|
||||
ServerFailed
|
||||
)
|
||||
|
||||
// The enumerated reasons for revoking a certificate. See RFC 5280.
|
||||
const (
|
||||
Unspecified = iota
|
||||
KeyCompromise = iota
|
||||
CACompromise = iota
|
||||
AffiliationChanged = iota
|
||||
Superseded = iota
|
||||
CessationOfOperation = iota
|
||||
CertificateHold = iota
|
||||
_ = iota
|
||||
RemoveFromCRL = iota
|
||||
PrivilegeWithdrawn = iota
|
||||
AACompromise = iota
|
||||
)
|
||||
|
||||
// Request represents an OCSP request. See RFC 6960.
|
||||
type Request struct {
|
||||
HashAlgorithm crypto.Hash
|
||||
IssuerNameHash []byte
|
||||
IssuerKeyHash []byte
|
||||
SerialNumber *big.Int
|
||||
}
|
||||
|
||||
// Response represents an OCSP response containing a single SingleResponse. See
|
||||
// RFC 6960.
|
||||
type Response struct {
|
||||
// Status is one of {Good, Revoked, Unknown}
|
||||
Status int
|
||||
SerialNumber *big.Int
|
||||
ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time
|
||||
RevocationReason int
|
||||
Certificate *x509.Certificate
|
||||
// TBSResponseData contains the raw bytes of the signed response. If
|
||||
// Certificate is nil then this can be used to verify Signature.
|
||||
TBSResponseData []byte
|
||||
Signature []byte
|
||||
SignatureAlgorithm x509.SignatureAlgorithm
|
||||
|
||||
// Extensions contains raw X.509 extensions from the singleExtensions field
|
||||
// of the OCSP response. When parsing certificates, this can be used to
|
||||
// extract non-critical extensions that are not parsed by this package. When
|
||||
// marshaling OCSP responses, the Extensions field is ignored, see
|
||||
// ExtraExtensions.
|
||||
Extensions []pkix.Extension
|
||||
|
||||
// ExtraExtensions contains extensions to be copied, raw, into any marshaled
|
||||
// OCSP response (in the singleExtensions field). Values override any
|
||||
// extensions that would otherwise be produced based on the other fields. The
|
||||
// ExtraExtensions field is not populated when parsing certificates, see
|
||||
// Extensions.
|
||||
ExtraExtensions []pkix.Extension
|
||||
}
|
||||
|
||||
// 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
|
||||
// signature. That signature is checked by ParseResponse and only
|
||||
// resp.Certificate remains to be validated.
|
||||
func (resp *Response) CheckSignatureFrom(issuer *x509.Certificate) error {
|
||||
return issuer.CheckSignature(resp.SignatureAlgorithm, resp.TBSResponseData, resp.Signature)
|
||||
}
|
||||
|
||||
// ParseError results from an invalid OCSP response.
|
||||
type ParseError string
|
||||
|
||||
func (p ParseError) Error() string {
|
||||
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
|
||||
// it will be used to validate the signature or embedded certificate.
|
||||
//
|
||||
// Invalid signatures or parse failures will result in a ParseError. Error
|
||||
// responses will result in a ResponseError.
|
||||
func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) {
|
||||
var resp responseASN1
|
||||
rest, err := asn1.Unmarshal(bytes, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rest) > 0 {
|
||||
return nil, ParseError("trailing data in OCSP response")
|
||||
}
|
||||
|
||||
if status := ResponseStatus(resp.Status); status != Success {
|
||||
return nil, ResponseError{status}
|
||||
}
|
||||
|
||||
if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
|
||||
return nil, ParseError("bad OCSP response type")
|
||||
}
|
||||
|
||||
var basicResp basicResponse
|
||||
rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(basicResp.Certificates) > 1 {
|
||||
return nil, ParseError("OCSP response contains bad number of certificates")
|
||||
}
|
||||
|
||||
if len(basicResp.TBSResponseData.Responses) != 1 {
|
||||
return nil, ParseError("OCSP response contains bad number of responses")
|
||||
}
|
||||
|
||||
ret := &Response{
|
||||
TBSResponseData: basicResp.TBSResponseData.Raw,
|
||||
Signature: basicResp.Signature.RightAlign(),
|
||||
SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm),
|
||||
}
|
||||
|
||||
if len(basicResp.Certificates) > 0 {
|
||||
ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ret.CheckSignatureFrom(ret.Certificate); err != nil {
|
||||
return nil, ParseError("bad OCSP signature")
|
||||
}
|
||||
|
||||
if issuer != nil {
|
||||
if err := issuer.CheckSignature(ret.Certificate.SignatureAlgorithm, ret.Certificate.RawTBSCertificate, ret.Certificate.Signature); err != nil {
|
||||
return nil, ParseError("bad signature on embedded certificate")
|
||||
}
|
||||
}
|
||||
} else if issuer != nil {
|
||||
if err := ret.CheckSignatureFrom(issuer); err != nil {
|
||||
return nil, ParseError("bad OCSP signature")
|
||||
}
|
||||
}
|
||||
|
||||
r := basicResp.TBSResponseData.Responses[0]
|
||||
|
||||
for _, ext := range r.SingleExtensions {
|
||||
if ext.Critical {
|
||||
return nil, ParseError("unsupported critical extension")
|
||||
}
|
||||
}
|
||||
ret.Extensions = r.SingleExtensions
|
||||
|
||||
ret.SerialNumber = r.CertID.SerialNumber
|
||||
|
||||
switch {
|
||||
case bool(r.Good):
|
||||
ret.Status = Good
|
||||
case bool(r.Unknown):
|
||||
ret.Status = Unknown
|
||||
default:
|
||||
ret.Status = Revoked
|
||||
ret.RevokedAt = r.Revoked.RevocationTime
|
||||
ret.RevocationReason = int(r.Revoked.Reason)
|
||||
}
|
||||
|
||||
ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
|
||||
ret.ThisUpdate = r.ThisUpdate
|
||||
ret.NextUpdate = r.NextUpdate
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// RequestOptions contains options for constructing OCSP requests.
|
||||
type RequestOptions struct {
|
||||
// Hash contains the hash function that should be used when
|
||||
// constructing the OCSP request. If zero, SHA-1 will be used.
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
func (opts *RequestOptions) hash() crypto.Hash {
|
||||
if opts == nil || opts.Hash == 0 {
|
||||
// SHA-1 is nearly universally used in OCSP.
|
||||
return crypto.SHA1
|
||||
}
|
||||
return opts.Hash
|
||||
}
|
||||
|
||||
// CreateRequest returns a DER-encoded, OCSP request for the status of cert. If
|
||||
// opts is nil then sensible defaults are used.
|
||||
func CreateRequest(cert, issuer *x509.Certificate, opts *RequestOptions) ([]byte, error) {
|
||||
hashFunc := opts.hash()
|
||||
|
||||
// OCSP seems to be the only place where these raw hash identifiers are
|
||||
// used. I took the following from
|
||||
// http://msdn.microsoft.com/en-us/library/ff635603.aspx
|
||||
var hashOID asn1.ObjectIdentifier
|
||||
hashOID, ok := hashOIDs[hashFunc]
|
||||
if !ok {
|
||||
return nil, x509.ErrUnsupportedAlgorithm
|
||||
}
|
||||
|
||||
if !hashFunc.Available() {
|
||||
return nil, x509.ErrUnsupportedAlgorithm
|
||||
}
|
||||
h := opts.hash().New()
|
||||
|
||||
var publicKeyInfo struct {
|
||||
Algorithm pkix.AlgorithmIdentifier
|
||||
PublicKey asn1.BitString
|
||||
}
|
||||
if _, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h.Write(publicKeyInfo.PublicKey.RightAlign())
|
||||
issuerKeyHash := h.Sum(nil)
|
||||
|
||||
h.Reset()
|
||||
h.Write(issuer.RawSubject)
|
||||
issuerNameHash := h.Sum(nil)
|
||||
|
||||
return asn1.Marshal(ocspRequest{
|
||||
tbsRequest{
|
||||
Version: 0,
|
||||
RequestList: []request{
|
||||
{
|
||||
Cert: certID{
|
||||
pkix.AlgorithmIdentifier{
|
||||
Algorithm: hashOID,
|
||||
Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */},
|
||||
},
|
||||
issuerNameHash,
|
||||
issuerKeyHash,
|
||||
cert.SerialNumber,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 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(),
|
||||
SingleExtensions: template.ExtraExtensions,
|
||||
}
|
||||
|
||||
switch template.Status {
|
||||
case Good:
|
||||
innerResponse.Good = true
|
||||
case Unknown:
|
||||
innerResponse.Unknown = true
|
||||
case Revoked:
|
||||
innerResponse.Revoked = revokedInfo{
|
||||
RevocationTime: template.RevokedAt.UTC(),
|
||||
Reason: asn1.Enumerated(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: asn1.Enumerated(Success),
|
||||
Response: responseBytes{
|
||||
ResponseType: idPKIXOCSPBasic,
|
||||
Response: responseDER,
|
||||
},
|
||||
})
|
||||
}
|
584
vendor/golang.org/x/crypto/ocsp/ocsp_test.go
generated
vendored
Normal file
584
vendor/golang.org/x/crypto/ocsp/ocsp_test.go
generated
vendored
Normal file
|
@ -0,0 +1,584 @@
|
|||
// Copyright 2013 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 ocsp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestOCSPDecode(t *testing.T) {
|
||||
responseBytes, _ := hex.DecodeString(ocspResponseHex)
|
||||
resp, err := ParseResponse(responseBytes, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
expected := Response{
|
||||
Status: Good,
|
||||
SerialNumber: big.NewInt(0x1d0fa),
|
||||
RevocationReason: Unspecified,
|
||||
ThisUpdate: time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC),
|
||||
NextUpdate: time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC),
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resp.ThisUpdate, expected.ThisUpdate) {
|
||||
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resp.NextUpdate, expected.NextUpdate) {
|
||||
t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
|
||||
}
|
||||
|
||||
if resp.Status != expected.Status {
|
||||
t.Errorf("resp.Status: got %d, want %d", resp.Status, expected.Status)
|
||||
}
|
||||
|
||||
if resp.SerialNumber.Cmp(expected.SerialNumber) != 0 {
|
||||
t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, expected.SerialNumber)
|
||||
}
|
||||
|
||||
if resp.RevocationReason != expected.RevocationReason {
|
||||
t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOCSPDecodeWithoutCert(t *testing.T) {
|
||||
responseBytes, _ := hex.DecodeString(ocspResponseWithoutCertHex)
|
||||
_, err := ParseResponse(responseBytes, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOCSPDecodeWithExtensions(t *testing.T) {
|
||||
responseBytes, _ := hex.DecodeString(ocspResponseWithCriticalExtensionHex)
|
||||
_, err := ParseResponse(responseBytes, nil)
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
responseBytes, _ = hex.DecodeString(ocspResponseWithExtensionHex)
|
||||
response, err := ParseResponse(responseBytes, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(response.Extensions) != 1 {
|
||||
t.Errorf("len(response.Extensions): got %v, want %v", len(response.Extensions), 1)
|
||||
}
|
||||
|
||||
extensionBytes := response.Extensions[0].Value
|
||||
expectedBytes, _ := hex.DecodeString(ocspExtensionValueHex)
|
||||
if !bytes.Equal(extensionBytes, expectedBytes) {
|
||||
t.Errorf("response.Extensions[0]: got %x, want %x", extensionBytes, expectedBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOCSPSignature(t *testing.T) {
|
||||
issuerCert, _ := hex.DecodeString(startComHex)
|
||||
issuer, err := x509.ParseCertificate(issuerCert)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
response, _ := hex.DecodeString(ocspResponseHex)
|
||||
if _, err := ParseResponse(response, issuer); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOCSPRequest(t *testing.T) {
|
||||
leafCert, _ := hex.DecodeString(leafCertHex)
|
||||
cert, 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)
|
||||
}
|
||||
|
||||
request, err := CreateRequest(cert, issuer, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
extensionBytes, _ := hex.DecodeString(ocspExtensionValueHex)
|
||||
extensions := []pkix.Extension{
|
||||
pkix.Extension{
|
||||
Id: ocspExtensionOID,
|
||||
Critical: false,
|
||||
Value: extensionBytes,
|
||||
},
|
||||
}
|
||||
|
||||
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: KeyCompromise,
|
||||
Certificate: responder,
|
||||
ExtraExtensions: extensions,
|
||||
}
|
||||
|
||||
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 !reflect.DeepEqual(resp.Extensions, template.ExtraExtensions) {
|
||||
t.Errorf("resp.Extensions: got %v, want %v", resp.Extensions, template.ExtraExtensions)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorResponse(t *testing.T) {
|
||||
responseBytes, _ := hex.DecodeString(errorResponseHex)
|
||||
_, err := ParseResponse(responseBytes, nil)
|
||||
|
||||
respErr, ok := err.(ResponseError)
|
||||
if !ok {
|
||||
t.Fatalf("expected ResponseError from ParseResponse but got %#v", err)
|
||||
}
|
||||
if respErr.Status != Malformed {
|
||||
t.Fatalf("expected Malformed status from ParseResponse but got %d", respErr.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// This OCSP response was taken from Thawte's public OCSP responder.
|
||||
// To recreate:
|
||||
// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
|
||||
// Copy and paste the first certificate into /tmp/cert.crt and the second into
|
||||
// /tmp/intermediate.crt
|
||||
// $ openssl ocsp -issuer /tmp/intermediate.crt -cert /tmp/cert.crt -url http://ocsp.thawte.com -resp_text -respout /tmp/ocsp.der
|
||||
// Then hex encode the result:
|
||||
// $ python -c 'print file("/tmp/ocsp.der", "r").read().encode("hex")'
|
||||
|
||||
const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048206a23082069e3081" +
|
||||
"c9a14e304c310b300906035504061302494c31163014060355040a130d5374617274436f" +
|
||||
"6d204c74642e312530230603550403131c5374617274436f6d20436c6173732031204f43" +
|
||||
"5350205369676e6572180f32303130303730373137333531375a30663064303c30090605" +
|
||||
"2b0e03021a050004146568874f40750f016a3475625e1f5c93e5a26d580414eb4234d098" +
|
||||
"b0ab9ff41b6b08f7cc642eef0e2c45020301d0fa8000180f323031303037303731353031" +
|
||||
"30355aa011180f32303130303730373138333531375a300d06092a864886f70d01010505" +
|
||||
"000382010100ab557ff070d1d7cebbb5f0ec91a15c3fed22eb2e1b8244f1b84545f013a4" +
|
||||
"fb46214c5e3fbfbebb8a56acc2b9db19f68fd3c3201046b3824d5ba689f99864328710cb" +
|
||||
"467195eb37d84f539e49f859316b32964dc3e47e36814ce94d6c56dd02733b1d0802f7ff" +
|
||||
"4eebdbbd2927dcf580f16cbc290f91e81b53cb365e7223f1d6e20a88ea064104875e0145" +
|
||||
"672b20fc14829d51ca122f5f5d77d3ad6c83889c55c7dc43680ba2fe3cef8b05dbcabdc0" +
|
||||
"d3e09aaf9725597f8c858c2fa38c0d6aed2e6318194420dd1a1137445d13e1c97ab47896" +
|
||||
"17a4e08925f46f867b72e3a4dc1f08cb870b2b0717f7207faa0ac512e628a029aba7457a" +
|
||||
"e63dcf3281e2162d9349a08204ba308204b6308204b23082039aa003020102020101300d" +
|
||||
"06092a864886f70d010105050030818c310b300906035504061302494c31163014060355" +
|
||||
"040a130d5374617274436f6d204c74642e312b3029060355040b13225365637572652044" +
|
||||
"69676974616c204365727469666963617465205369676e696e6731383036060355040313" +
|
||||
"2f5374617274436f6d20436c6173732031205072696d61727920496e7465726d65646961" +
|
||||
"746520536572766572204341301e170d3037313032353030323330365a170d3132313032" +
|
||||
"333030323330365a304c310b300906035504061302494c31163014060355040a130d5374" +
|
||||
"617274436f6d204c74642e312530230603550403131c5374617274436f6d20436c617373" +
|
||||
"2031204f435350205369676e657230820122300d06092a864886f70d0101010500038201" +
|
||||
"0f003082010a0282010100b9561b4c45318717178084e96e178df2255e18ed8d8ecc7c2b" +
|
||||
"7b51a6c1c2e6bf0aa3603066f132fe10ae97b50e99fa24b83fc53dd2777496387d14e1c3" +
|
||||
"a9b6a4933e2ac12413d085570a95b8147414a0bc007c7bcf222446ef7f1a156d7ea1c577" +
|
||||
"fc5f0facdfd42eb0f5974990cb2f5cefebceef4d1bdc7ae5c1075c5a99a93171f2b0845b" +
|
||||
"4ff0864e973fcfe32f9d7511ff87a3e943410c90a4493a306b6944359340a9ca96f02b66" +
|
||||
"ce67f028df2980a6aaee8d5d5d452b8b0eb93f923cc1e23fcccbdbe7ffcb114d08fa7a6a" +
|
||||
"3c404f825d1a0e715935cf623a8c7b59670014ed0622f6089a9447a7a19010f7fe58f841" +
|
||||
"29a2765ea367824d1c3bb2fda308530203010001a382015c30820158300c0603551d1301" +
|
||||
"01ff04023000300b0603551d0f0404030203a8301e0603551d250417301506082b060105" +
|
||||
"0507030906092b0601050507300105301d0603551d0e0416041445e0a36695414c5dd449" +
|
||||
"bc00e33cdcdbd2343e173081a80603551d230481a030819d8014eb4234d098b0ab9ff41b" +
|
||||
"6b08f7cc642eef0e2c45a18181a47f307d310b300906035504061302494c311630140603" +
|
||||
"55040a130d5374617274436f6d204c74642e312b3029060355040b132253656375726520" +
|
||||
"4469676974616c204365727469666963617465205369676e696e67312930270603550403" +
|
||||
"13205374617274436f6d2043657274696669636174696f6e20417574686f726974798201" +
|
||||
"0a30230603551d12041c301a8618687474703a2f2f7777772e737461727473736c2e636f" +
|
||||
"6d2f302c06096086480186f842010d041f161d5374617274436f6d205265766f63617469" +
|
||||
"6f6e20417574686f72697479300d06092a864886f70d01010505000382010100182d2215" +
|
||||
"8f0fc0291324fa8574c49bb8ff2835085adcbf7b7fc4191c397ab6951328253fffe1e5ec" +
|
||||
"2a7da0d50fca1a404e6968481366939e666c0a6209073eca57973e2fefa9ed1718e8176f" +
|
||||
"1d85527ff522c08db702e3b2b180f1cbff05d98128252cf0f450f7dd2772f4188047f19d" +
|
||||
"c85317366f94bc52d60f453a550af58e308aaab00ced33040b62bf37f5b1ab2a4f7f0f80" +
|
||||
"f763bf4d707bc8841d7ad9385ee2a4244469260b6f2bf085977af9074796048ecc2f9d48" +
|
||||
"a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
|
||||
"6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"
|
||||
|
||||
const startComHex = "308206343082041ca003020102020118300d06092a864886f70d0101050500307d310b30" +
|
||||
"0906035504061302494c31163014060355040a130d5374617274436f6d204c74642e312b" +
|
||||
"3029060355040b1322536563757265204469676974616c20436572746966696361746520" +
|
||||
"5369676e696e6731293027060355040313205374617274436f6d20436572746966696361" +
|
||||
"74696f6e20417574686f72697479301e170d3037313032343230353431375a170d313731" +
|
||||
"3032343230353431375a30818c310b300906035504061302494c31163014060355040a13" +
|
||||
"0d5374617274436f6d204c74642e312b3029060355040b13225365637572652044696769" +
|
||||
"74616c204365727469666963617465205369676e696e67313830360603550403132f5374" +
|
||||
"617274436f6d20436c6173732031205072696d61727920496e7465726d65646961746520" +
|
||||
"53657276657220434130820122300d06092a864886f70d01010105000382010f00308201" +
|
||||
"0a0282010100b689c6acef09527807ac9263d0f44418188480561f91aee187fa3250b4d3" +
|
||||
"4706f0e6075f700e10f71dc0ce103634855a0f92ac83c6ac58523fba38e8fce7a724e240" +
|
||||
"a60876c0926e9e2a6d4d3f6e61200adb59ded27d63b33e46fefa215118d7cd30a6ed076e" +
|
||||
"3b7087b4f9faebee823c056f92f7a4dc0a301e9373fe07cad75f809d225852ae06da8b87" +
|
||||
"2369b0e42ad8ea83d2bdf371db705a280faf5a387045123f304dcd3baf17e50fcba0a95d" +
|
||||
"48aab16150cb34cd3c5cc30be810c08c9bf0030362feb26c3e720eee1c432ac9480e5739" +
|
||||
"c43121c810c12c87fe5495521f523c31129b7fe7c0a0a559d5e28f3ef0d5a8e1d77031a9" +
|
||||
"c4b3cfaf6d532f06f4a70203010001a38201ad308201a9300f0603551d130101ff040530" +
|
||||
"030101ff300e0603551d0f0101ff040403020106301d0603551d0e04160414eb4234d098" +
|
||||
"b0ab9ff41b6b08f7cc642eef0e2c45301f0603551d230418301680144e0bef1aa4405ba5" +
|
||||
"17698730ca346843d041aef2306606082b06010505070101045a3058302706082b060105" +
|
||||
"05073001861b687474703a2f2f6f6373702e737461727473736c2e636f6d2f6361302d06" +
|
||||
"082b060105050730028621687474703a2f2f7777772e737461727473736c2e636f6d2f73" +
|
||||
"667363612e637274305b0603551d1f045430523027a025a0238621687474703a2f2f7777" +
|
||||
"772e737461727473736c2e636f6d2f73667363612e63726c3027a025a023862168747470" +
|
||||
"3a2f2f63726c2e737461727473736c2e636f6d2f73667363612e63726c3081800603551d" +
|
||||
"20047930773075060b2b0601040181b5370102013066302e06082b060105050702011622" +
|
||||
"687474703a2f2f7777772e737461727473736c2e636f6d2f706f6c6963792e7064663034" +
|
||||
"06082b060105050702011628687474703a2f2f7777772e737461727473736c2e636f6d2f" +
|
||||
"696e7465726d6564696174652e706466300d06092a864886f70d01010505000382020100" +
|
||||
"2109493ea5886ee00b8b48da314d8ff75657a2e1d36257e9b556f38545753be5501f048b" +
|
||||
"e6a05a3ee700ae85d0fbff200364cbad02e1c69172f8a34dd6dee8cc3fa18aa2e37c37a7" +
|
||||
"c64f8f35d6f4d66e067bdd21d9cf56ffcb302249fe8904f385e5aaf1e71fe875904dddf9" +
|
||||
"46f74234f745580c110d84b0c6da5d3ef9019ee7e1da5595be741c7bfc4d144fac7e5547" +
|
||||
"7d7bf4a50d491e95e8f712c1ccff76a62547d0f37535be97b75816ebaa5c786fec5330af" +
|
||||
"ea044dcca902e3f0b60412f630b1113d904e5664d7dc3c435f7339ef4baf87ebf6fe6888" +
|
||||
"4472ead207c669b0c1a18bef1749d761b145485f3b2021e95bb2ccf4d7e931f50b15613b" +
|
||||
"7a94e3ebd9bc7f94ae6ae3626296a8647cb887f399327e92a252bebbf865cfc9f230fc8b" +
|
||||
"c1c2a696d75f89e15c3480f58f47072fb491bfb1a27e5f4b5ad05b9f248605515a690365" +
|
||||
"434971c5e06f94346bf61bd8a9b04c7e53eb8f48dfca33b548fa364a1a53a6330cd089cd" +
|
||||
"4915cd89313c90c072d7654b52358a461144b93d8e2865a63e799e5c084429adb035112e" +
|
||||
"214eb8d2e7103e5d8483b3c3c2e4d2c6fd094b7409ddf1b3d3193e800da20b19f038e7c5" +
|
||||
"c2afe223db61e29d5c6e2089492e236ab262c145b49faf8ba7f1223bf87de290d07a19fb" +
|
||||
"4a4ce3d27d5f4a8303ed27d6239e6b8db459a2d9ef6c8229dd75193c3f4c108defbb7527" +
|
||||
"d2ae83a7a8ce5ba7"
|
||||
|
||||
const ocspResponseWithoutCertHex = "308201d40a0100a08201cd308201c906092b0601050507300101048201ba3082" +
|
||||
"01b630819fa2160414884451ff502a695e2d88f421bad90cf2cecbea7c180f3230313330" +
|
||||
"3631383037323434335a30743072304a300906052b0e03021a0500041448b60d38238df8" +
|
||||
"456e4ee5843ea394111802979f0414884451ff502a695e2d88f421bad90cf2cecbea7c02" +
|
||||
"1100f78b13b946fc9635d8ab49de9d2148218000180f3230313330363138303732343433" +
|
||||
"5aa011180f32303133303632323037323434335a300d06092a864886f70d010105050003" +
|
||||
"82010100103e18b3d297a5e7a6c07a4fc52ac46a15c0eba96f3be17f0ffe84de5b8c8e05" +
|
||||
"5a8f577586a849dc4abd6440eb6fedde4622451e2823c1cbf3558b4e8184959c9fe96eff" +
|
||||
"8bc5f95866c58c6d087519faabfdae37e11d9874f1bc0db292208f645dd848185e4dd38b" +
|
||||
"6a8547dfa7b74d514a8470015719064d35476b95bebb03d4d2845c5ca15202d2784878f2" +
|
||||
"0f904c24f09736f044609e9c271381713400e563023d212db422236440c6f377bbf24b2b" +
|
||||
"9e7dec8698e36a8df68b7592ad3489fb2937afb90eb85d2aa96b81c94c25057dbd4759d9" +
|
||||
"20a1a65c7f0b6427a224b3c98edd96b9b61f706099951188b0289555ad30a216fb774651" +
|
||||
"5a35fca2e054dfa8"
|
||||
|
||||
// PKIX nonce extension
|
||||
var ocspExtensionOID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 2}
|
||||
var ocspExtensionValueHex = "0403000000"
|
||||
|
||||
const ocspResponseWithCriticalExtensionHex = "308204fe0a0100a08204f7308204f306092b0601050507300101048204e4308204e03081" +
|
||||
"dba003020100a11b3019311730150603550403130e4f43535020526573706f6e64657218" +
|
||||
"0f32303136303130343137303130305a3081a53081a23049300906052b0e03021a050004" +
|
||||
"14c0fe0278fc99188891b3f212e9c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b21317" +
|
||||
"7e6f8d157cd4f60210017f77deb3bcbb235d44ccc7dba62e72a116180f32303130303730" +
|
||||
"373135303130355aa0030a0101180f32303130303730373135303130355aa011180f3230" +
|
||||
"3130303730373138333531375aa1193017301506092b06010505073001020101ff040504" +
|
||||
"03000000300d06092a864886f70d01010b0500038201010031c730ca60a7a0d92d8e4010" +
|
||||
"911b469de95b4d27e89de6537552436237967694f76f701cf6b45c932bd308bca4a8d092" +
|
||||
"5c604ba94796903091d9e6c000178e72c1f0a24a277dd262835af5d17d3f9d7869606c9f" +
|
||||
"e7c8e708a41645699895beee38bfa63bb46296683761c5d1d65439b8ab868dc3017c9eeb" +
|
||||
"b70b82dbf3a31c55b457d48bb9e82b335ed49f445042eaf606b06a3e0639824924c89c63" +
|
||||
"eccddfe85e6694314138b2536f5e15e07085d0f6e26d4b2f8244bab0d70de07283ac6384" +
|
||||
"a0501fc3dea7cf0adfd4c7f34871080900e252ddc403e3f0265f2a704af905d3727504ed" +
|
||||
"28f3214a219d898a022463c78439799ca81c8cbafdbcec34ea937cd6a08202ea308202e6" +
|
||||
"308202e2308201caa003020102020101300d06092a864886f70d01010b05003019311730" +
|
||||
"150603550403130e4f43535020526573706f6e646572301e170d31353031333031353530" +
|
||||
"33335a170d3136303133303135353033335a3019311730150603550403130e4f43535020" +
|
||||
"526573706f6e64657230820122300d06092a864886f70d01010105000382010f00308201" +
|
||||
"0a0282010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef1099f0f6616e" +
|
||||
"c5265b56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df1701dc6ccfbc" +
|
||||
"bec75a70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074ffde8a99d5b72" +
|
||||
"3350f0a112076614b12ef79c78991b119453445acf2416ab0046b540db14c9fc0f27b898" +
|
||||
"9ad0f63aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa77e7332971c7d" +
|
||||
"285b6a04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f1290bafd97e6" +
|
||||
"55b1049a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb96222b12ace31" +
|
||||
"a77dcf920334dc94581b0203010001a3353033300e0603551d0f0101ff04040302078030" +
|
||||
"130603551d25040c300a06082b06010505070309300c0603551d130101ff04023000300d" +
|
||||
"06092a864886f70d01010b05000382010100718012761b5063e18f0dc44644d8e6ab8612" +
|
||||
"31c15fd5357805425d82aec1de85bf6d3e30fce205e3e3b8b795bbe52e40a439286d2288" +
|
||||
"9064f4aeeb150359b9425f1da51b3a5c939018555d13ac42c565a0603786a919328f3267" +
|
||||
"09dce52c22ad958ecb7873b9771d1148b1c4be2efe80ba868919fc9f68b6090c2f33c156" +
|
||||
"d67156e42766a50b5d51e79637b7e58af74c2a951b1e642fa7741fec982cc937de37eff5" +
|
||||
"9e2005d5939bfc031589ca143e6e8ab83f40ee08cc20a6b4a95a318352c28d18528dcaf9" +
|
||||
"66705de17afa19d6e8ae91ddf33179d16ebb6ac2c69cae8373d408ebf8c55308be6c04d9" +
|
||||
"3a25439a94299a65a709756c7a3e568be049d5c38839"
|
||||
|
||||
const ocspResponseWithExtensionHex = "308204fb0a0100a08204f4308204f006092b0601050507300101048204e1308204dd3081" +
|
||||
"d8a003020100a11b3019311730150603550403130e4f43535020526573706f6e64657218" +
|
||||
"0f32303136303130343136353930305a3081a230819f3049300906052b0e03021a050004" +
|
||||
"14c0fe0278fc99188891b3f212e9c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b21317" +
|
||||
"7e6f8d157cd4f60210017f77deb3bcbb235d44ccc7dba62e72a116180f32303130303730" +
|
||||
"373135303130355aa0030a0101180f32303130303730373135303130355aa011180f3230" +
|
||||
"3130303730373138333531375aa1163014301206092b0601050507300102040504030000" +
|
||||
"00300d06092a864886f70d01010b05000382010100c09a33e0b2324c852421bb83f85ac9" +
|
||||
"9113f5426012bd2d2279a8166e9241d18a33c870894250622ffc7ed0c4601b16d624f90b" +
|
||||
"779265442cdb6868cf40ab304ab4b66e7315ed02cf663b1601d1d4751772b31bc299db23" +
|
||||
"9aebac78ed6797c06ed815a7a8d18d63cfbb609cafb47ec2e89e37db255216eb09307848" +
|
||||
"d01be0a3e943653c78212b96ff524b74c9ec456b17cdfb950cc97645c577b2e09ff41dde" +
|
||||
"b03afb3adaa381cc0f7c1d95663ef22a0f72f2c45613ae8e2b2d1efc96e8463c7d1d8a1d" +
|
||||
"7e3b35df8fe73a301fc3f804b942b2b3afa337ff105fc1462b7b1c1d75eb4566c8665e59" +
|
||||
"f80393b0adbf8004ff6c3327ed34f007cb4a3348a7d55e06e3a08202ea308202e6308202" +
|
||||
"e2308201caa003020102020101300d06092a864886f70d01010b05003019311730150603" +
|
||||
"550403130e4f43535020526573706f6e646572301e170d3135303133303135353033335a" +
|
||||
"170d3136303133303135353033335a3019311730150603550403130e4f43535020526573" +
|
||||
"706f6e64657230820122300d06092a864886f70d01010105000382010f003082010a0282" +
|
||||
"010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef1099f0f6616ec5265b" +
|
||||
"56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df1701dc6ccfbcbec75a" +
|
||||
"70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074ffde8a99d5b723350f0" +
|
||||
"a112076614b12ef79c78991b119453445acf2416ab0046b540db14c9fc0f27b8989ad0f6" +
|
||||
"3aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa77e7332971c7d285b6a" +
|
||||
"04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f1290bafd97e655b104" +
|
||||
"9a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb96222b12ace31a77dcf" +
|
||||
"920334dc94581b0203010001a3353033300e0603551d0f0101ff04040302078030130603" +
|
||||
"551d25040c300a06082b06010505070309300c0603551d130101ff04023000300d06092a" +
|
||||
"864886f70d01010b05000382010100718012761b5063e18f0dc44644d8e6ab861231c15f" +
|
||||
"d5357805425d82aec1de85bf6d3e30fce205e3e3b8b795bbe52e40a439286d22889064f4" +
|
||||
"aeeb150359b9425f1da51b3a5c939018555d13ac42c565a0603786a919328f326709dce5" +
|
||||
"2c22ad958ecb7873b9771d1148b1c4be2efe80ba868919fc9f68b6090c2f33c156d67156" +
|
||||
"e42766a50b5d51e79637b7e58af74c2a951b1e642fa7741fec982cc937de37eff59e2005" +
|
||||
"d5939bfc031589ca143e6e8ab83f40ee08cc20a6b4a95a318352c28d18528dcaf966705d" +
|
||||
"e17afa19d6e8ae91ddf33179d16ebb6ac2c69cae8373d408ebf8c55308be6c04d93a2543" +
|
||||
"9a94299a65a709756c7a3e568be049d5c38839"
|
||||
|
||||
const ocspRequestHex = "3051304f304d304b3049300906052b0e03021a05000414c0fe0278fc99188891b3f212e9" +
|
||||
"c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210017f77deb3" +
|
||||
"bcbb235d44ccc7dba62e72"
|
||||
|
||||
const leafCertHex = "308203c830820331a0030201020210017f77deb3bcbb235d44ccc7dba62e72300d06092a" +
|
||||
"864886f70d01010505003081ba311f301d060355040a1316566572695369676e20547275" +
|
||||
"7374204e6574776f726b31173015060355040b130e566572695369676e2c20496e632e31" +
|
||||
"333031060355040b132a566572695369676e20496e7465726e6174696f6e616c20536572" +
|
||||
"766572204341202d20436c617373203331493047060355040b13407777772e7665726973" +
|
||||
"69676e2e636f6d2f43505320496e636f72702e6279205265662e204c494142494c495459" +
|
||||
"204c54442e286329393720566572695369676e301e170d3132303632313030303030305a" +
|
||||
"170d3133313233313233353935395a3068310b3009060355040613025553311330110603" +
|
||||
"550408130a43616c69666f726e6961311230100603550407130950616c6f20416c746f31" +
|
||||
"173015060355040a130e46616365626f6f6b2c20496e632e311730150603550403140e2a" +
|
||||
"2e66616365626f6f6b2e636f6d30819f300d06092a864886f70d010101050003818d0030" +
|
||||
"818902818100ae94b171e2deccc1693e051063240102e0689ae83c39b6b3e74b97d48d7b" +
|
||||
"23689100b0b496ee62f0e6d356bcf4aa0f50643402f5d1766aa972835a7564723f39bbef" +
|
||||
"5290ded9bcdbf9d3d55dfad23aa03dc604c54d29cf1d4b3bdbd1a809cfae47b44c7eae17" +
|
||||
"c5109bee24a9cf4a8d911bb0fd0415ae4c3f430aa12a557e2ae10203010001a382011e30" +
|
||||
"82011a30090603551d130402300030440603551d20043d303b3039060b6086480186f845" +
|
||||
"01071703302a302806082b06010505070201161c68747470733a2f2f7777772e76657269" +
|
||||
"7369676e2e636f6d2f727061303c0603551d1f043530333031a02fa02d862b687474703a" +
|
||||
"2f2f535652496e746c2d63726c2e766572697369676e2e636f6d2f535652496e746c2e63" +
|
||||
"726c301d0603551d250416301406082b0601050507030106082b06010505070302300b06" +
|
||||
"03551d0f0404030205a0303406082b0601050507010104283026302406082b0601050507" +
|
||||
"30018618687474703a2f2f6f6373702e766572697369676e2e636f6d30270603551d1104" +
|
||||
"20301e820e2a2e66616365626f6f6b2e636f6d820c66616365626f6f6b2e636f6d300d06" +
|
||||
"092a864886f70d0101050500038181005b6c2b75f8ed30aa51aad36aba595e555141951f" +
|
||||
"81a53b447910ac1f76ff78fc2781616b58f3122afc1c87010425e9ed43df1a7ba6498060" +
|
||||
"67e2688af03db58c7df4ee03309a6afc247ccb134dc33e54c6bc1d5133a532a73273b1d7" +
|
||||
"9cadc08e7e1a83116d34523340b0305427a21742827c98916698ee7eaf8c3bdd71700817"
|
||||
|
||||
const issuerCertHex = "30820383308202eca003020102021046fcebbab4d02f0f926098233f93078f300d06092a" +
|
||||
"864886f70d0101050500305f310b300906035504061302555331173015060355040a130e" +
|
||||
"566572695369676e2c20496e632e31373035060355040b132e436c617373203320507562" +
|
||||
"6c6963205072696d6172792043657274696669636174696f6e20417574686f7269747930" +
|
||||
"1e170d3937303431373030303030305a170d3136313032343233353935395a3081ba311f" +
|
||||
"301d060355040a1316566572695369676e205472757374204e6574776f726b3117301506" +
|
||||
"0355040b130e566572695369676e2c20496e632e31333031060355040b132a5665726953" +
|
||||
"69676e20496e7465726e6174696f6e616c20536572766572204341202d20436c61737320" +
|
||||
"3331493047060355040b13407777772e766572697369676e2e636f6d2f43505320496e63" +
|
||||
"6f72702e6279205265662e204c494142494c495459204c54442e28632939372056657269" +
|
||||
"5369676e30819f300d06092a864886f70d010101050003818d0030818902818100d88280" +
|
||||
"e8d619027d1f85183925a2652be1bfd405d3bce6363baaf04c6c5bb6e7aa3c734555b2f1" +
|
||||
"bdea9742ed9a340a15d4a95cf54025ddd907c132b2756cc4cabba3fe56277143aa63f530" +
|
||||
"3e9328e5faf1093bf3b74d4e39f75c495ab8c11dd3b28afe70309542cbfe2b518b5a3c3a" +
|
||||
"f9224f90b202a7539c4f34e7ab04b27b6f0203010001a381e33081e0300f0603551d1304" +
|
||||
"0830060101ff02010030440603551d20043d303b3039060b6086480186f8450107010130" +
|
||||
"2a302806082b06010505070201161c68747470733a2f2f7777772e766572697369676e2e" +
|
||||
"636f6d2f43505330340603551d25042d302b06082b0601050507030106082b0601050507" +
|
||||
"030206096086480186f8420401060a6086480186f845010801300b0603551d0f04040302" +
|
||||
"0106301106096086480186f842010104040302010630310603551d1f042a30283026a024" +
|
||||
"a0228620687474703a2f2f63726c2e766572697369676e2e636f6d2f706361332e63726c" +
|
||||
"300d06092a864886f70d010105050003818100408e4997968a73dd8e4def3e61b7caa062" +
|
||||
"adf40e0abb753de26ed82cc7bff4b98c369bcaa2d09c724639f6a682036511c4bcbf2da6" +
|
||||
"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"
|
||||
|
||||
const errorResponseHex = "30030a0101"
|
66
vendor/golang.org/x/crypto/sha3/doc.go
generated
vendored
Normal file
66
vendor/golang.org/x/crypto/sha3/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2014 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 implements the SHA-3 fixed-output-length hash functions and
|
||||
// the SHAKE variable-output-length hash functions defined by FIPS-202.
|
||||
//
|
||||
// Both types of hash function use the "sponge" construction and the Keccak
|
||||
// permutation. For a detailed specification see http://keccak.noekeon.org/
|
||||
//
|
||||
//
|
||||
// Guidance
|
||||
//
|
||||
// If you aren't sure what function you need, use SHAKE256 with at least 64
|
||||
// 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
|
||||
// output.
|
||||
//
|
||||
//
|
||||
// Security strengths
|
||||
//
|
||||
// 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-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 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
|
||||
// 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 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 the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
|
||||
//
|
||||
//
|
||||
// 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 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
|
||||
// against all attacks. This means, in particular, that SHA3-256 only has
|
||||
// 128-bit collision resistance, because its output length is 32 bytes.
|
||||
package sha3 // import "golang.org/x/crypto/sha3"
|
65
vendor/golang.org/x/crypto/sha3/hashes.go
generated
vendored
Normal file
65
vendor/golang.org/x/crypto/sha3/hashes.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2014 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
|
||||
|
||||
// This file provides functions for creating instances of the SHA-3
|
||||
// and SHAKE hash functions, as well as utility functions for hashing
|
||||
// bytes.
|
||||
|
||||
import (
|
||||
"hash"
|
||||
)
|
||||
|
||||
// New224 creates a new SHA3-224 hash.
|
||||
// Its generic security strength is 224 bits against preimage attacks,
|
||||
// and 112 bits against collision attacks.
|
||||
func New224() hash.Hash { return &state{rate: 144, outputLen: 28, dsbyte: 0x06} }
|
||||
|
||||
// New256 creates a new SHA3-256 hash.
|
||||
// Its generic security strength is 256 bits against preimage attacks,
|
||||
// and 128 bits against collision attacks.
|
||||
func New256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x06} }
|
||||
|
||||
// New384 creates a new SHA3-384 hash.
|
||||
// Its generic security strength is 384 bits against preimage attacks,
|
||||
// and 192 bits against collision attacks.
|
||||
func New384() hash.Hash { return &state{rate: 104, outputLen: 48, dsbyte: 0x06} }
|
||||
|
||||
// New512 creates a new SHA3-512 hash.
|
||||
// Its generic security strength is 512 bits against preimage attacks,
|
||||
// and 256 bits against collision attacks.
|
||||
func New512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x06} }
|
||||
|
||||
// Sum224 returns the SHA3-224 digest of the data.
|
||||
func Sum224(data []byte) (digest [28]byte) {
|
||||
h := New224()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum256 returns the SHA3-256 digest of the data.
|
||||
func Sum256(data []byte) (digest [32]byte) {
|
||||
h := New256()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum384 returns the SHA3-384 digest of the data.
|
||||
func Sum384(data []byte) (digest [48]byte) {
|
||||
h := New384()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
||||
|
||||
// Sum512 returns the SHA3-512 digest of the data.
|
||||
func Sum512(data []byte) (digest [64]byte) {
|
||||
h := New512()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
}
|
410
vendor/golang.org/x/crypto/sha3/keccakf.go
generated
vendored
Normal file
410
vendor/golang.org/x/crypto/sha3/keccakf.go
generated
vendored
Normal file
|
@ -0,0 +1,410 @@
|
|||
// Copyright 2014 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
|
||||
|
||||
// rc stores the round constants for use in the ι step.
|
||||
var rc = [24]uint64{
|
||||
0x0000000000000001,
|
||||
0x0000000000008082,
|
||||
0x800000000000808A,
|
||||
0x8000000080008000,
|
||||
0x000000000000808B,
|
||||
0x0000000080000001,
|
||||
0x8000000080008081,
|
||||
0x8000000000008009,
|
||||
0x000000000000008A,
|
||||
0x0000000000000088,
|
||||
0x0000000080008009,
|
||||
0x000000008000000A,
|
||||
0x000000008000808B,
|
||||
0x800000000000008B,
|
||||
0x8000000000008089,
|
||||
0x8000000000008003,
|
||||
0x8000000000008002,
|
||||
0x8000000000000080,
|
||||
0x000000000000800A,
|
||||
0x800000008000000A,
|
||||
0x8000000080008081,
|
||||
0x8000000000008080,
|
||||
0x0000000080000001,
|
||||
0x8000000080008008,
|
||||
}
|
||||
|
||||
// keccakF1600 applies the Keccak permutation to a 1600b-wide
|
||||
// state represented as a slice of 25 uint64s.
|
||||
func keccakF1600(a *[25]uint64) {
|
||||
// Implementation translated from Keccak-inplace.c
|
||||
// in the keccak reference code.
|
||||
var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
|
||||
|
||||
for i := 0; i < 24; i += 4 {
|
||||
// Combines the 5 steps in each round into 2 steps.
|
||||
// Unrolls 4 rounds per loop and spreads some steps across rounds.
|
||||
|
||||
// Round 1
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[6] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[12] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[18] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[24] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i]
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[16] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[22] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[3] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[1] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[7] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[19] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[11] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[23] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[4] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[2] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[8] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[14] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 2
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[16] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[7] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[23] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[14] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1]
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[11] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[2] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[18] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[6] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[22] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[4] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[1] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[8] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[24] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[12] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[3] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[19] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 3
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[11] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[22] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[8] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[19] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2]
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[1] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[12] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[23] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[16] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[2] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[24] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[6] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[3] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[14] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[7] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[18] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[4] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
// Round 4
|
||||
bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
|
||||
bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
|
||||
bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
|
||||
bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
|
||||
bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
|
||||
d0 = bc4 ^ (bc1<<1 | bc1>>63)
|
||||
d1 = bc0 ^ (bc2<<1 | bc2>>63)
|
||||
d2 = bc1 ^ (bc3<<1 | bc3>>63)
|
||||
d3 = bc2 ^ (bc4<<1 | bc4>>63)
|
||||
d4 = bc3 ^ (bc0<<1 | bc0>>63)
|
||||
|
||||
bc0 = a[0] ^ d0
|
||||
t = a[1] ^ d1
|
||||
bc1 = t<<44 | t>>(64-44)
|
||||
t = a[2] ^ d2
|
||||
bc2 = t<<43 | t>>(64-43)
|
||||
t = a[3] ^ d3
|
||||
bc3 = t<<21 | t>>(64-21)
|
||||
t = a[4] ^ d4
|
||||
bc4 = t<<14 | t>>(64-14)
|
||||
a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3]
|
||||
a[1] = bc1 ^ (bc3 &^ bc2)
|
||||
a[2] = bc2 ^ (bc4 &^ bc3)
|
||||
a[3] = bc3 ^ (bc0 &^ bc4)
|
||||
a[4] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[5] ^ d0
|
||||
bc2 = t<<3 | t>>(64-3)
|
||||
t = a[6] ^ d1
|
||||
bc3 = t<<45 | t>>(64-45)
|
||||
t = a[7] ^ d2
|
||||
bc4 = t<<61 | t>>(64-61)
|
||||
t = a[8] ^ d3
|
||||
bc0 = t<<28 | t>>(64-28)
|
||||
t = a[9] ^ d4
|
||||
bc1 = t<<20 | t>>(64-20)
|
||||
a[5] = bc0 ^ (bc2 &^ bc1)
|
||||
a[6] = bc1 ^ (bc3 &^ bc2)
|
||||
a[7] = bc2 ^ (bc4 &^ bc3)
|
||||
a[8] = bc3 ^ (bc0 &^ bc4)
|
||||
a[9] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[10] ^ d0
|
||||
bc4 = t<<18 | t>>(64-18)
|
||||
t = a[11] ^ d1
|
||||
bc0 = t<<1 | t>>(64-1)
|
||||
t = a[12] ^ d2
|
||||
bc1 = t<<6 | t>>(64-6)
|
||||
t = a[13] ^ d3
|
||||
bc2 = t<<25 | t>>(64-25)
|
||||
t = a[14] ^ d4
|
||||
bc3 = t<<8 | t>>(64-8)
|
||||
a[10] = bc0 ^ (bc2 &^ bc1)
|
||||
a[11] = bc1 ^ (bc3 &^ bc2)
|
||||
a[12] = bc2 ^ (bc4 &^ bc3)
|
||||
a[13] = bc3 ^ (bc0 &^ bc4)
|
||||
a[14] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[15] ^ d0
|
||||
bc1 = t<<36 | t>>(64-36)
|
||||
t = a[16] ^ d1
|
||||
bc2 = t<<10 | t>>(64-10)
|
||||
t = a[17] ^ d2
|
||||
bc3 = t<<15 | t>>(64-15)
|
||||
t = a[18] ^ d3
|
||||
bc4 = t<<56 | t>>(64-56)
|
||||
t = a[19] ^ d4
|
||||
bc0 = t<<27 | t>>(64-27)
|
||||
a[15] = bc0 ^ (bc2 &^ bc1)
|
||||
a[16] = bc1 ^ (bc3 &^ bc2)
|
||||
a[17] = bc2 ^ (bc4 &^ bc3)
|
||||
a[18] = bc3 ^ (bc0 &^ bc4)
|
||||
a[19] = bc4 ^ (bc1 &^ bc0)
|
||||
|
||||
t = a[20] ^ d0
|
||||
bc3 = t<<41 | t>>(64-41)
|
||||
t = a[21] ^ d1
|
||||
bc4 = t<<2 | t>>(64-2)
|
||||
t = a[22] ^ d2
|
||||
bc0 = t<<62 | t>>(64-62)
|
||||
t = a[23] ^ d3
|
||||
bc1 = t<<55 | t>>(64-55)
|
||||
t = a[24] ^ d4
|
||||
bc2 = t<<39 | t>>(64-39)
|
||||
a[20] = bc0 ^ (bc2 &^ bc1)
|
||||
a[21] = bc1 ^ (bc3 &^ bc2)
|
||||
a[22] = bc2 ^ (bc4 &^ bc3)
|
||||
a[23] = bc3 ^ (bc0 &^ bc4)
|
||||
a[24] = bc4 ^ (bc1 &^ bc0)
|
||||
}
|
||||
}
|
18
vendor/golang.org/x/crypto/sha3/register.go
generated
vendored
Normal file
18
vendor/golang.org/x/crypto/sha3/register.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2014 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 go1.4
|
||||
|
||||
package sha3
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA3_224, New224)
|
||||
crypto.RegisterHash(crypto.SHA3_256, New256)
|
||||
crypto.RegisterHash(crypto.SHA3_384, New384)
|
||||
crypto.RegisterHash(crypto.SHA3_512, New512)
|
||||
}
|
193
vendor/golang.org/x/crypto/sha3/sha3.go
generated
vendored
Normal file
193
vendor/golang.org/x/crypto/sha3/sha3.go
generated
vendored
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright 2014 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
|
||||
|
||||
// spongeDirection indicates the direction bytes are flowing through the sponge.
|
||||
type spongeDirection int
|
||||
|
||||
const (
|
||||
// spongeAbsorbing indicates that the sponge is absorbing input.
|
||||
spongeAbsorbing spongeDirection = iota
|
||||
// spongeSqueezing indicates that the sponge is being squeezed.
|
||||
spongeSqueezing
|
||||
)
|
||||
|
||||
const (
|
||||
// maxRate is the maximum size of the internal buffer. SHAKE-256
|
||||
// currently needs the largest buffer.
|
||||
maxRate = 168
|
||||
)
|
||||
|
||||
type state struct {
|
||||
// Generic sponge components.
|
||||
a [25]uint64 // main state of the hash
|
||||
buf []byte // points into storage
|
||||
rate int // the number of bytes of state to use
|
||||
|
||||
// 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 // whether the sponge is absorbing or squeezing
|
||||
}
|
||||
|
||||
// BlockSize returns the rate of sponge underlying this hash function.
|
||||
func (d *state) BlockSize() int { return d.rate }
|
||||
|
||||
// Size returns the output size of the hash function in bytes.
|
||||
func (d *state) Size() int { return d.outputLen }
|
||||
|
||||
// Reset clears the internal state by zeroing the sponge state and
|
||||
// the byte buffer, and setting Sponge.state to absorbing.
|
||||
func (d *state) Reset() {
|
||||
// Zero the permutation's state.
|
||||
for i := range d.a {
|
||||
d.a[i] = 0
|
||||
}
|
||||
d.state = spongeAbsorbing
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
|
||||
func (d *state) clone() *state {
|
||||
ret := *d
|
||||
if ret.state == spongeAbsorbing {
|
||||
ret.buf = ret.storage[:len(ret.buf)]
|
||||
} else {
|
||||
ret.buf = ret.storage[d.rate-cap(d.buf) : d.rate]
|
||||
}
|
||||
|
||||
return &ret
|
||||
}
|
||||
|
||||
// permute applies the KeccakF-1600 permutation. It handles
|
||||
// any input-output buffering.
|
||||
func (d *state) permute() {
|
||||
switch d.state {
|
||||
case spongeAbsorbing:
|
||||
// If we're absorbing, we need to xor the input into the state
|
||||
// before applying the permutation.
|
||||
xorIn(d, d.buf)
|
||||
d.buf = d.storage[:0]
|
||||
keccakF1600(&d.a)
|
||||
case spongeSqueezing:
|
||||
// If we're squeezing, we need to apply the permutatin before
|
||||
// copying more output.
|
||||
keccakF1600(&d.a)
|
||||
d.buf = d.storage[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
}
|
||||
|
||||
// pads appends the domain separation bits in dsbyte, applies
|
||||
// the multi-bitrate 10..1 padding rule, and permutes the state.
|
||||
func (d *state) padAndPermute(dsbyte byte) {
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
// Pad with this instance's domain-separator bits. We know that there's
|
||||
// at least one byte of space in d.buf because, if it were full,
|
||||
// permute would have been called to empty it. dsbyte also contains the
|
||||
// first one bit for the padding. See the comment in the state struct.
|
||||
d.buf = append(d.buf, dsbyte)
|
||||
zerosStart := len(d.buf)
|
||||
d.buf = d.storage[:d.rate]
|
||||
for i := zerosStart; i < d.rate; i++ {
|
||||
d.buf[i] = 0
|
||||
}
|
||||
// This adds the final one bit for the padding. Because of the way that
|
||||
// bits are numbered from the LSB upwards, the final bit is the MSB of
|
||||
// the last byte.
|
||||
d.buf[d.rate-1] ^= 0x80
|
||||
// Apply the permutation
|
||||
d.permute()
|
||||
d.state = spongeSqueezing
|
||||
d.buf = d.storage[:d.rate]
|
||||
copyOut(d, d.buf)
|
||||
}
|
||||
|
||||
// Write absorbs more data into the hash's state. It produces an error
|
||||
// if more data is written to the ShakeHash after writing
|
||||
func (d *state) Write(p []byte) (written int, err error) {
|
||||
if d.state != spongeAbsorbing {
|
||||
panic("sha3: write to sponge after read")
|
||||
}
|
||||
if d.buf == nil {
|
||||
d.buf = d.storage[:0]
|
||||
}
|
||||
written = len(p)
|
||||
|
||||
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.
|
||||
xorIn(d, p[:d.rate])
|
||||
p = p[d.rate:]
|
||||
keccakF1600(&d.a)
|
||||
} else {
|
||||
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
|
||||
todo := d.rate - len(d.buf)
|
||||
if todo > len(p) {
|
||||
todo = len(p)
|
||||
}
|
||||
d.buf = append(d.buf, p[:todo]...)
|
||||
p = p[todo:]
|
||||
|
||||
// If the sponge is full, apply the permutation.
|
||||
if len(d.buf) == d.rate {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||
func (d *state) Read(out []byte) (n int, err error) {
|
||||
// If we're still absorbing, pad and apply the permutation.
|
||||
if d.state == spongeAbsorbing {
|
||||
d.padAndPermute(d.dsbyte)
|
||||
}
|
||||
|
||||
n = len(out)
|
||||
|
||||
// Now, do the squeezing.
|
||||
for len(out) > 0 {
|
||||
n := copy(out, d.buf)
|
||||
d.buf = d.buf[n:]
|
||||
out = out[n:]
|
||||
|
||||
// Apply the permutation if we've squeezed the sponge dry.
|
||||
if len(d.buf) == 0 {
|
||||
d.permute()
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Sum applies padding to the hash state and then squeezes out the desired
|
||||
// number of output bytes.
|
||||
func (d *state) Sum(in []byte) []byte {
|
||||
// Make a copy of the original hash so that caller can keep writing
|
||||
// and summing.
|
||||
dup := d.clone()
|
||||
hash := make([]byte, dup.outputLen)
|
||||
dup.Read(hash)
|
||||
return append(in, hash...)
|
||||
}
|
306
vendor/golang.org/x/crypto/sha3/sha3_test.go
generated
vendored
Normal file
306
vendor/golang.org/x/crypto/sha3/sha3_test.go
generated
vendored
Normal file
|
@ -0,0 +1,306 @@
|
|||
// Copyright 2014 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
|
||||
|
||||
// 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 bitwise testvectors
|
||||
// published by NIST in the draft of FIPS-202.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"hash"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
testString = "brekeccakkeccak koax koax"
|
||||
katFilename = "testdata/keccakKats.json.deflate"
|
||||
)
|
||||
|
||||
// Internal-use instances of SHAKE used to test against KATs.
|
||||
func newHashShake128() hash.Hash {
|
||||
return &state{rate: 168, dsbyte: 0x1f, outputLen: 512}
|
||||
}
|
||||
func newHashShake256() hash.Hash {
|
||||
return &state{rate: 136, dsbyte: 0x1f, outputLen: 512}
|
||||
}
|
||||
|
||||
// testDigests contains functions returning hash.Hash instances
|
||||
// with output-length equal to the KAT length for both SHA-3 and
|
||||
// SHAKE instances.
|
||||
var testDigests = map[string]func() hash.Hash{
|
||||
"SHA3-224": New224,
|
||||
"SHA3-256": New256,
|
||||
"SHA3-384": New384,
|
||||
"SHA3-512": New512,
|
||||
"SHAKE128": newHashShake128,
|
||||
"SHAKE256": newHashShake256,
|
||||
}
|
||||
|
||||
// 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 a hex-encoded string into a raw byte string.
|
||||
func decodeHex(s string) []byte {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// structs used to marshal JSON test-cases.
|
||||
type KeccakKats struct {
|
||||
Kats map[string][]struct {
|
||||
Digest string `json:"digest"`
|
||||
Length int64 `json:"length"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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]()
|
||||
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) {
|
||||
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
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestAppend checks that appending works when reallocation is necessary.
|
||||
func TestAppend(t *testing.T) {
|
||||
testUnalignedAndGeneric(t, func(impl string) {
|
||||
d := New224()
|
||||
|
||||
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 := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
|
||||
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
|
||||
t.Errorf("%s: got %s, want %s", impl, 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) {
|
||||
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...)
|
||||
}
|
||||
if !bytes.Equal(ref, multiple) {
|
||||
t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
|
||||
func sequentialBytes(size int) []byte {
|
||||
result := make([]byte, size)
|
||||
for i := range result {
|
||||
result[i] = byte(i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BenchmarkPermutationFunction measures the speed of the permutation function
|
||||
// with no input data.
|
||||
func BenchmarkPermutationFunction(b *testing.B) {
|
||||
b.SetBytes(int64(200))
|
||||
var lanes [25]uint64
|
||||
for i := 0; i < b.N; i++ {
|
||||
keccakF1600(&lanes)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 * num))
|
||||
b.StartTimer()
|
||||
|
||||
var state []byte
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < num; j++ {
|
||||
h.Write(data)
|
||||
}
|
||||
state = h.Sum(state[:0])
|
||||
}
|
||||
b.StopTimer()
|
||||
h.Reset()
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
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)
|
||||
}
|
60
vendor/golang.org/x/crypto/sha3/shake.go
generated
vendored
Normal file
60
vendor/golang.org/x/crypto/sha3/shake.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2014 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
|
||||
|
||||
// This file defines the ShakeHash interface, and provides
|
||||
// functions for creating SHAKE instances, as well as utility
|
||||
// functions for hashing bytes to arbitrary-length output.
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// ShakeHash defines the interface to hash functions that
|
||||
// support arbitrary-length output.
|
||||
type ShakeHash interface {
|
||||
// Write absorbs more data into the hash's state. It panics if input is
|
||||
// written to it after output has been read from it.
|
||||
io.Writer
|
||||
|
||||
// Read reads more output from the hash; reading affects the hash's
|
||||
// state. (ShakeHash.Read is thus very different from Hash.Sum)
|
||||
// It never returns an error.
|
||||
io.Reader
|
||||
|
||||
// Clone returns a copy of the ShakeHash in its current state.
|
||||
Clone() ShakeHash
|
||||
|
||||
// Reset resets the ShakeHash to its initial state.
|
||||
Reset()
|
||||
}
|
||||
|
||||
func (d *state) Clone() ShakeHash {
|
||||
return d.clone()
|
||||
}
|
||||
|
||||
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 128 bits against all attacks if at
|
||||
// least 32 bytes of its output are used.
|
||||
func NewShake128() ShakeHash { return &state{rate: 168, dsbyte: 0x1f} }
|
||||
|
||||
// NewShake256 creates a new SHAKE128 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 256 bits against all attacks if
|
||||
// at least 64 bytes of its output are used.
|
||||
func NewShake256() ShakeHash { return &state{rate: 136, dsbyte: 0x1f} }
|
||||
|
||||
// ShakeSum128 writes an arbitrary-length digest of data into hash.
|
||||
func ShakeSum128(hash, data []byte) {
|
||||
h := NewShake128()
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
||||
|
||||
// ShakeSum256 writes an arbitrary-length digest of data into hash.
|
||||
func ShakeSum256(hash, data []byte) {
|
||||
h := NewShake256()
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
BIN
vendor/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
generated
vendored
Normal file
BIN
vendor/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
generated
vendored
Normal file
Binary file not shown.
16
vendor/golang.org/x/crypto/sha3/xor.go
generated
vendored
Normal file
16
vendor/golang.org/x/crypto/sha3/xor.go
generated
vendored
Normal file
|
@ -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"
|
28
vendor/golang.org/x/crypto/sha3/xor_generic.go
generated
vendored
Normal file
28
vendor/golang.org/x/crypto/sha3/xor_generic.go
generated
vendored
Normal file
|
@ -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:]
|
||||
}
|
||||
}
|
58
vendor/golang.org/x/crypto/sha3/xor_unaligned.go
generated
vendored
Normal file
58
vendor/golang.org/x/crypto/sha3/xor_unaligned.go
generated
vendored
Normal file
|
@ -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"
|
892
vendor/golang.org/x/crypto/ssh/terminal/terminal.go
generated
vendored
Normal file
892
vendor/golang.org/x/crypto/ssh/terminal/terminal.go
generated
vendored
Normal file
|
@ -0,0 +1,892 @@
|
|||
// Copyright 2011 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 terminal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// EscapeCodes contains escape sequences that can be written to the terminal in
|
||||
// order to achieve different styles of text.
|
||||
type EscapeCodes struct {
|
||||
// Foreground colors
|
||||
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
|
||||
|
||||
// Reset all attributes
|
||||
Reset []byte
|
||||
}
|
||||
|
||||
var vt100EscapeCodes = EscapeCodes{
|
||||
Black: []byte{keyEscape, '[', '3', '0', 'm'},
|
||||
Red: []byte{keyEscape, '[', '3', '1', 'm'},
|
||||
Green: []byte{keyEscape, '[', '3', '2', 'm'},
|
||||
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
|
||||
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
|
||||
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
|
||||
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
|
||||
White: []byte{keyEscape, '[', '3', '7', 'm'},
|
||||
|
||||
Reset: []byte{keyEscape, '[', '0', 'm'},
|
||||
}
|
||||
|
||||
// Terminal contains the state for running a VT100 terminal that is capable of
|
||||
// reading lines of input.
|
||||
type Terminal struct {
|
||||
// AutoCompleteCallback, if non-null, is called for each keypress with
|
||||
// the full input line and the current position of the cursor (in
|
||||
// bytes, as an index into |line|). If it returns ok=false, the key
|
||||
// press is processed normally. Otherwise it returns a replacement line
|
||||
// and the new cursor position.
|
||||
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
|
||||
|
||||
// Escape contains a pointer to the escape codes for this terminal.
|
||||
// It's always a valid pointer, although the escape codes themselves
|
||||
// may be empty if the terminal doesn't support them.
|
||||
Escape *EscapeCodes
|
||||
|
||||
// lock protects the terminal and the state in this object from
|
||||
// concurrent processing of a key press and a Write() call.
|
||||
lock sync.Mutex
|
||||
|
||||
c io.ReadWriter
|
||||
prompt []rune
|
||||
|
||||
// line is the current line being entered.
|
||||
line []rune
|
||||
// pos is the logical position of the cursor in line
|
||||
pos int
|
||||
// echo is true if local echo is enabled
|
||||
echo bool
|
||||
// pasteActive is true iff there is a bracketed paste operation in
|
||||
// progress.
|
||||
pasteActive bool
|
||||
|
||||
// cursorX contains the current X value of the cursor where the left
|
||||
// edge is 0. cursorY contains the row number where the first row of
|
||||
// the current line is 0.
|
||||
cursorX, cursorY int
|
||||
// maxLine is the greatest value of cursorY so far.
|
||||
maxLine int
|
||||
|
||||
termWidth, termHeight int
|
||||
|
||||
// outBuf contains the terminal data to be sent.
|
||||
outBuf []byte
|
||||
// remainder contains the remainder of any partial key sequences after
|
||||
// a read. It aliases into inBuf.
|
||||
remainder []byte
|
||||
inBuf [256]byte
|
||||
|
||||
// history contains previously entered commands so that they can be
|
||||
// accessed with the up and down keys.
|
||||
history stRingBuffer
|
||||
// historyIndex stores the currently accessed history entry, where zero
|
||||
// means the immediately previous entry.
|
||||
historyIndex int
|
||||
// When navigating up and down the history it's possible to return to
|
||||
// the incomplete, initial line. That value is stored in
|
||||
// historyPending.
|
||||
historyPending string
|
||||
}
|
||||
|
||||
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
|
||||
// a local terminal, that terminal must first have been put into raw mode.
|
||||
// prompt is a string that is written at the start of each input line (i.e.
|
||||
// "> ").
|
||||
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
|
||||
return &Terminal{
|
||||
Escape: &vt100EscapeCodes,
|
||||
c: c,
|
||||
prompt: []rune(prompt),
|
||||
termWidth: 80,
|
||||
termHeight: 24,
|
||||
echo: true,
|
||||
historyIndex: -1,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
keyCtrlD = 4
|
||||
keyCtrlU = 21
|
||||
keyEnter = '\r'
|
||||
keyEscape = 27
|
||||
keyBackspace = 127
|
||||
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
|
||||
keyUp
|
||||
keyDown
|
||||
keyLeft
|
||||
keyRight
|
||||
keyAltLeft
|
||||
keyAltRight
|
||||
keyHome
|
||||
keyEnd
|
||||
keyDeleteWord
|
||||
keyDeleteLine
|
||||
keyClearScreen
|
||||
keyPasteStart
|
||||
keyPasteEnd
|
||||
)
|
||||
|
||||
var pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
|
||||
var pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
|
||||
|
||||
// bytesToKey tries to parse a key sequence from b. If successful, it returns
|
||||
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
|
||||
func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
|
||||
if len(b) == 0 {
|
||||
return utf8.RuneError, nil
|
||||
}
|
||||
|
||||
if !pasteActive {
|
||||
switch b[0] {
|
||||
case 1: // ^A
|
||||
return keyHome, b[1:]
|
||||
case 5: // ^E
|
||||
return keyEnd, b[1:]
|
||||
case 8: // ^H
|
||||
return keyBackspace, b[1:]
|
||||
case 11: // ^K
|
||||
return keyDeleteLine, b[1:]
|
||||
case 12: // ^L
|
||||
return keyClearScreen, b[1:]
|
||||
case 23: // ^W
|
||||
return keyDeleteWord, b[1:]
|
||||
}
|
||||
}
|
||||
|
||||
if b[0] != keyEscape {
|
||||
if !utf8.FullRune(b) {
|
||||
return utf8.RuneError, b
|
||||
}
|
||||
r, l := utf8.DecodeRune(b)
|
||||
return r, b[l:]
|
||||
}
|
||||
|
||||
if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
|
||||
switch b[2] {
|
||||
case 'A':
|
||||
return keyUp, b[3:]
|
||||
case 'B':
|
||||
return keyDown, b[3:]
|
||||
case 'C':
|
||||
return keyRight, b[3:]
|
||||
case 'D':
|
||||
return keyLeft, b[3:]
|
||||
case 'H':
|
||||
return keyHome, b[3:]
|
||||
case 'F':
|
||||
return keyEnd, b[3:]
|
||||
}
|
||||
}
|
||||
|
||||
if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
|
||||
switch b[5] {
|
||||
case 'C':
|
||||
return keyAltRight, b[6:]
|
||||
case 'D':
|
||||
return keyAltLeft, b[6:]
|
||||
}
|
||||
}
|
||||
|
||||
if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
|
||||
return keyPasteStart, b[6:]
|
||||
}
|
||||
|
||||
if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
|
||||
return keyPasteEnd, b[6:]
|
||||
}
|
||||
|
||||
// If we get here then we have a key that we don't recognise, or a
|
||||
// partial sequence. It's not clear how one should find the end of a
|
||||
// sequence without knowing them all, but it seems that [a-zA-Z~] only
|
||||
// appears at the end of a sequence.
|
||||
for i, c := range b[0:] {
|
||||
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
|
||||
return keyUnknown, b[i+1:]
|
||||
}
|
||||
}
|
||||
|
||||
return utf8.RuneError, b
|
||||
}
|
||||
|
||||
// queue appends data to the end of t.outBuf
|
||||
func (t *Terminal) queue(data []rune) {
|
||||
t.outBuf = append(t.outBuf, []byte(string(data))...)
|
||||
}
|
||||
|
||||
var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
|
||||
var space = []rune{' '}
|
||||
|
||||
func isPrintable(key rune) bool {
|
||||
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
|
||||
return key >= 32 && !isInSurrogateArea
|
||||
}
|
||||
|
||||
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
|
||||
// given, logical position in the text.
|
||||
func (t *Terminal) moveCursorToPos(pos int) {
|
||||
if !t.echo {
|
||||
return
|
||||
}
|
||||
|
||||
x := visualLength(t.prompt) + pos
|
||||
y := x / t.termWidth
|
||||
x = x % t.termWidth
|
||||
|
||||
up := 0
|
||||
if y < t.cursorY {
|
||||
up = t.cursorY - y
|
||||
}
|
||||
|
||||
down := 0
|
||||
if y > t.cursorY {
|
||||
down = y - t.cursorY
|
||||
}
|
||||
|
||||
left := 0
|
||||
if x < t.cursorX {
|
||||
left = t.cursorX - x
|
||||
}
|
||||
|
||||
right := 0
|
||||
if x > t.cursorX {
|
||||
right = x - t.cursorX
|
||||
}
|
||||
|
||||
t.cursorX = x
|
||||
t.cursorY = y
|
||||
t.move(up, down, left, right)
|
||||
}
|
||||
|
||||
func (t *Terminal) move(up, down, left, right int) {
|
||||
movement := make([]rune, 3*(up+down+left+right))
|
||||
m := movement
|
||||
for i := 0; i < up; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'A'
|
||||
m = m[3:]
|
||||
}
|
||||
for i := 0; i < down; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'B'
|
||||
m = m[3:]
|
||||
}
|
||||
for i := 0; i < left; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'D'
|
||||
m = m[3:]
|
||||
}
|
||||
for i := 0; i < right; i++ {
|
||||
m[0] = keyEscape
|
||||
m[1] = '['
|
||||
m[2] = 'C'
|
||||
m = m[3:]
|
||||
}
|
||||
|
||||
t.queue(movement)
|
||||
}
|
||||
|
||||
func (t *Terminal) clearLineToRight() {
|
||||
op := []rune{keyEscape, '[', 'K'}
|
||||
t.queue(op)
|
||||
}
|
||||
|
||||
const maxLineLength = 4096
|
||||
|
||||
func (t *Terminal) setLine(newLine []rune, newPos int) {
|
||||
if t.echo {
|
||||
t.moveCursorToPos(0)
|
||||
t.writeLine(newLine)
|
||||
for i := len(newLine); i < len(t.line); i++ {
|
||||
t.writeLine(space)
|
||||
}
|
||||
t.moveCursorToPos(newPos)
|
||||
}
|
||||
t.line = newLine
|
||||
t.pos = newPos
|
||||
}
|
||||
|
||||
func (t *Terminal) advanceCursor(places int) {
|
||||
t.cursorX += places
|
||||
t.cursorY += t.cursorX / t.termWidth
|
||||
if t.cursorY > t.maxLine {
|
||||
t.maxLine = t.cursorY
|
||||
}
|
||||
t.cursorX = t.cursorX % t.termWidth
|
||||
|
||||
if places > 0 && t.cursorX == 0 {
|
||||
// Normally terminals will advance the current position
|
||||
// when writing a character. But that doesn't happen
|
||||
// for the last character in a line. However, when
|
||||
// writing a character (except a new line) that causes
|
||||
// a line wrap, the position will be advanced two
|
||||
// places.
|
||||
//
|
||||
// So, if we are stopping at the end of a line, we
|
||||
// need to write a newline so that our cursor can be
|
||||
// advanced to the next line.
|
||||
t.outBuf = append(t.outBuf, '\n')
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Terminal) eraseNPreviousChars(n int) {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if t.pos < n {
|
||||
n = t.pos
|
||||
}
|
||||
t.pos -= n
|
||||
t.moveCursorToPos(t.pos)
|
||||
|
||||
copy(t.line[t.pos:], t.line[n+t.pos:])
|
||||
t.line = t.line[:len(t.line)-n]
|
||||
if t.echo {
|
||||
t.writeLine(t.line[t.pos:])
|
||||
for i := 0; i < n; i++ {
|
||||
t.queue(space)
|
||||
}
|
||||
t.advanceCursor(n)
|
||||
t.moveCursorToPos(t.pos)
|
||||
}
|
||||
}
|
||||
|
||||
// countToLeftWord returns then number of characters from the cursor to the
|
||||
// start of the previous word.
|
||||
func (t *Terminal) countToLeftWord() int {
|
||||
if t.pos == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
pos := t.pos - 1
|
||||
for pos > 0 {
|
||||
if t.line[pos] != ' ' {
|
||||
break
|
||||
}
|
||||
pos--
|
||||
}
|
||||
for pos > 0 {
|
||||
if t.line[pos] == ' ' {
|
||||
pos++
|
||||
break
|
||||
}
|
||||
pos--
|
||||
}
|
||||
|
||||
return t.pos - pos
|
||||
}
|
||||
|
||||
// countToRightWord returns then number of characters from the cursor to the
|
||||
// start of the next word.
|
||||
func (t *Terminal) countToRightWord() int {
|
||||
pos := t.pos
|
||||
for pos < len(t.line) {
|
||||
if t.line[pos] == ' ' {
|
||||
break
|
||||
}
|
||||
pos++
|
||||
}
|
||||
for pos < len(t.line) {
|
||||
if t.line[pos] != ' ' {
|
||||
break
|
||||
}
|
||||
pos++
|
||||
}
|
||||
return pos - t.pos
|
||||
}
|
||||
|
||||
// visualLength returns the number of visible glyphs in s.
|
||||
func visualLength(runes []rune) int {
|
||||
inEscapeSeq := false
|
||||
length := 0
|
||||
|
||||
for _, r := range runes {
|
||||
switch {
|
||||
case inEscapeSeq:
|
||||
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
|
||||
inEscapeSeq = false
|
||||
}
|
||||
case r == '\x1b':
|
||||
inEscapeSeq = true
|
||||
default:
|
||||
length++
|
||||
}
|
||||
}
|
||||
|
||||
return length
|
||||
}
|
||||
|
||||
// handleKey processes the given key and, optionally, returns a line of text
|
||||
// that the user has entered.
|
||||
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
|
||||
if t.pasteActive && key != keyEnter {
|
||||
t.addKeyToLine(key)
|
||||
return
|
||||
}
|
||||
|
||||
switch key {
|
||||
case keyBackspace:
|
||||
if t.pos == 0 {
|
||||
return
|
||||
}
|
||||
t.eraseNPreviousChars(1)
|
||||
case keyAltLeft:
|
||||
// move left by a word.
|
||||
t.pos -= t.countToLeftWord()
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyAltRight:
|
||||
// move right by a word.
|
||||
t.pos += t.countToRightWord()
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyLeft:
|
||||
if t.pos == 0 {
|
||||
return
|
||||
}
|
||||
t.pos--
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyRight:
|
||||
if t.pos == len(t.line) {
|
||||
return
|
||||
}
|
||||
t.pos++
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyHome:
|
||||
if t.pos == 0 {
|
||||
return
|
||||
}
|
||||
t.pos = 0
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyEnd:
|
||||
if t.pos == len(t.line) {
|
||||
return
|
||||
}
|
||||
t.pos = len(t.line)
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyUp:
|
||||
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
if t.historyIndex == -1 {
|
||||
t.historyPending = string(t.line)
|
||||
}
|
||||
t.historyIndex++
|
||||
runes := []rune(entry)
|
||||
t.setLine(runes, len(runes))
|
||||
case keyDown:
|
||||
switch t.historyIndex {
|
||||
case -1:
|
||||
return
|
||||
case 0:
|
||||
runes := []rune(t.historyPending)
|
||||
t.setLine(runes, len(runes))
|
||||
t.historyIndex--
|
||||
default:
|
||||
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
|
||||
if ok {
|
||||
t.historyIndex--
|
||||
runes := []rune(entry)
|
||||
t.setLine(runes, len(runes))
|
||||
}
|
||||
}
|
||||
case keyEnter:
|
||||
t.moveCursorToPos(len(t.line))
|
||||
t.queue([]rune("\r\n"))
|
||||
line = string(t.line)
|
||||
ok = true
|
||||
t.line = t.line[:0]
|
||||
t.pos = 0
|
||||
t.cursorX = 0
|
||||
t.cursorY = 0
|
||||
t.maxLine = 0
|
||||
case keyDeleteWord:
|
||||
// Delete zero or more spaces and then one or more characters.
|
||||
t.eraseNPreviousChars(t.countToLeftWord())
|
||||
case keyDeleteLine:
|
||||
// Delete everything from the current cursor position to the
|
||||
// end of line.
|
||||
for i := t.pos; i < len(t.line); i++ {
|
||||
t.queue(space)
|
||||
t.advanceCursor(1)
|
||||
}
|
||||
t.line = t.line[:t.pos]
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyCtrlD:
|
||||
// Erase the character under the current position.
|
||||
// The EOF case when the line is empty is handled in
|
||||
// readLine().
|
||||
if t.pos < len(t.line) {
|
||||
t.pos++
|
||||
t.eraseNPreviousChars(1)
|
||||
}
|
||||
case keyCtrlU:
|
||||
t.eraseNPreviousChars(t.pos)
|
||||
case keyClearScreen:
|
||||
// Erases the screen and moves the cursor to the home position.
|
||||
t.queue([]rune("\x1b[2J\x1b[H"))
|
||||
t.queue(t.prompt)
|
||||
t.cursorX, t.cursorY = 0, 0
|
||||
t.advanceCursor(visualLength(t.prompt))
|
||||
t.setLine(t.line, t.pos)
|
||||
default:
|
||||
if t.AutoCompleteCallback != nil {
|
||||
prefix := string(t.line[:t.pos])
|
||||
suffix := string(t.line[t.pos:])
|
||||
|
||||
t.lock.Unlock()
|
||||
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
|
||||
t.lock.Lock()
|
||||
|
||||
if completeOk {
|
||||
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
|
||||
return
|
||||
}
|
||||
}
|
||||
if !isPrintable(key) {
|
||||
return
|
||||
}
|
||||
if len(t.line) == maxLineLength {
|
||||
return
|
||||
}
|
||||
t.addKeyToLine(key)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// addKeyToLine inserts the given key at the current position in the current
|
||||
// line.
|
||||
func (t *Terminal) addKeyToLine(key rune) {
|
||||
if len(t.line) == cap(t.line) {
|
||||
newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
|
||||
copy(newLine, t.line)
|
||||
t.line = newLine
|
||||
}
|
||||
t.line = t.line[:len(t.line)+1]
|
||||
copy(t.line[t.pos+1:], t.line[t.pos:])
|
||||
t.line[t.pos] = key
|
||||
if t.echo {
|
||||
t.writeLine(t.line[t.pos:])
|
||||
}
|
||||
t.pos++
|
||||
t.moveCursorToPos(t.pos)
|
||||
}
|
||||
|
||||
func (t *Terminal) writeLine(line []rune) {
|
||||
for len(line) != 0 {
|
||||
remainingOnLine := t.termWidth - t.cursorX
|
||||
todo := len(line)
|
||||
if todo > remainingOnLine {
|
||||
todo = remainingOnLine
|
||||
}
|
||||
t.queue(line[:todo])
|
||||
t.advanceCursor(visualLength(line[:todo]))
|
||||
line = line[todo:]
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Terminal) Write(buf []byte) (n int, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
if t.cursorX == 0 && t.cursorY == 0 {
|
||||
// This is the easy case: there's nothing on the screen that we
|
||||
// have to move out of the way.
|
||||
return t.c.Write(buf)
|
||||
}
|
||||
|
||||
// We have a prompt and possibly user input on the screen. We
|
||||
// have to clear it first.
|
||||
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
|
||||
t.cursorX = 0
|
||||
t.clearLineToRight()
|
||||
|
||||
for t.cursorY > 0 {
|
||||
t.move(1 /* up */, 0, 0, 0)
|
||||
t.cursorY--
|
||||
t.clearLineToRight()
|
||||
}
|
||||
|
||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||
return
|
||||
}
|
||||
t.outBuf = t.outBuf[:0]
|
||||
|
||||
if n, err = t.c.Write(buf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.writeLine(t.prompt)
|
||||
if t.echo {
|
||||
t.writeLine(t.line)
|
||||
}
|
||||
|
||||
t.moveCursorToPos(t.pos)
|
||||
|
||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||
return
|
||||
}
|
||||
t.outBuf = t.outBuf[:0]
|
||||
return
|
||||
}
|
||||
|
||||
// ReadPassword temporarily changes the prompt and reads a password, without
|
||||
// echo, from the terminal.
|
||||
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
oldPrompt := t.prompt
|
||||
t.prompt = []rune(prompt)
|
||||
t.echo = false
|
||||
|
||||
line, err = t.readLine()
|
||||
|
||||
t.prompt = oldPrompt
|
||||
t.echo = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReadLine returns a line of input from the terminal.
|
||||
func (t *Terminal) ReadLine() (line string, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
return t.readLine()
|
||||
}
|
||||
|
||||
func (t *Terminal) readLine() (line string, err error) {
|
||||
// t.lock must be held at this point
|
||||
|
||||
if t.cursorX == 0 && t.cursorY == 0 {
|
||||
t.writeLine(t.prompt)
|
||||
t.c.Write(t.outBuf)
|
||||
t.outBuf = t.outBuf[:0]
|
||||
}
|
||||
|
||||
lineIsPasted := t.pasteActive
|
||||
|
||||
for {
|
||||
rest := t.remainder
|
||||
lineOk := false
|
||||
for !lineOk {
|
||||
var key rune
|
||||
key, rest = bytesToKey(rest, t.pasteActive)
|
||||
if key == utf8.RuneError {
|
||||
break
|
||||
}
|
||||
if !t.pasteActive {
|
||||
if key == keyCtrlD {
|
||||
if len(t.line) == 0 {
|
||||
return "", io.EOF
|
||||
}
|
||||
}
|
||||
if key == keyPasteStart {
|
||||
t.pasteActive = true
|
||||
if len(t.line) == 0 {
|
||||
lineIsPasted = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else if key == keyPasteEnd {
|
||||
t.pasteActive = false
|
||||
continue
|
||||
}
|
||||
if !t.pasteActive {
|
||||
lineIsPasted = false
|
||||
}
|
||||
line, lineOk = t.handleKey(key)
|
||||
}
|
||||
if len(rest) > 0 {
|
||||
n := copy(t.inBuf[:], rest)
|
||||
t.remainder = t.inBuf[:n]
|
||||
} else {
|
||||
t.remainder = nil
|
||||
}
|
||||
t.c.Write(t.outBuf)
|
||||
t.outBuf = t.outBuf[:0]
|
||||
if lineOk {
|
||||
if t.echo {
|
||||
t.historyIndex = -1
|
||||
t.history.Add(line)
|
||||
}
|
||||
if lineIsPasted {
|
||||
err = ErrPasteIndicator
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// t.remainder is a slice at the beginning of t.inBuf
|
||||
// containing a partial key sequence
|
||||
readBuf := t.inBuf[len(t.remainder):]
|
||||
var n int
|
||||
|
||||
t.lock.Unlock()
|
||||
n, err = t.c.Read(readBuf)
|
||||
t.lock.Lock()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.remainder = t.inBuf[:n+len(t.remainder)]
|
||||
}
|
||||
|
||||
panic("unreachable") // for Go 1.0.
|
||||
}
|
||||
|
||||
// SetPrompt sets the prompt to be used when reading subsequent lines.
|
||||
func (t *Terminal) SetPrompt(prompt string) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
t.prompt = []rune(prompt)
|
||||
}
|
||||
|
||||
func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
|
||||
// Move cursor to column zero at the start of the line.
|
||||
t.move(t.cursorY, 0, t.cursorX, 0)
|
||||
t.cursorX, t.cursorY = 0, 0
|
||||
t.clearLineToRight()
|
||||
for t.cursorY < numPrevLines {
|
||||
// Move down a line
|
||||
t.move(0, 1, 0, 0)
|
||||
t.cursorY++
|
||||
t.clearLineToRight()
|
||||
}
|
||||
// Move back to beginning.
|
||||
t.move(t.cursorY, 0, 0, 0)
|
||||
t.cursorX, t.cursorY = 0, 0
|
||||
|
||||
t.queue(t.prompt)
|
||||
t.advanceCursor(visualLength(t.prompt))
|
||||
t.writeLine(t.line)
|
||||
t.moveCursorToPos(t.pos)
|
||||
}
|
||||
|
||||
func (t *Terminal) SetSize(width, height int) error {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
if width == 0 {
|
||||
width = 1
|
||||
}
|
||||
|
||||
oldWidth := t.termWidth
|
||||
t.termWidth, t.termHeight = width, height
|
||||
|
||||
switch {
|
||||
case width == oldWidth:
|
||||
// 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
|
||||
// attempt to wrap them. For the former, repainting t.maxLine
|
||||
// works great, but that behaviour goes badly wrong in the case
|
||||
// of the latter because they have doubled every full line.
|
||||
|
||||
// We assume that we are working on a terminal that wraps lines
|
||||
// and adjust the cursor position based on every previous line
|
||||
// wrapping and turning into two. This causes the prompt on
|
||||
// xterms to move upwards, which isn't great, but it avoids a
|
||||
// huge mess with gnome-terminal.
|
||||
if t.cursorX >= t.termWidth {
|
||||
t.cursorX = t.termWidth - 1
|
||||
}
|
||||
t.cursorY *= 2
|
||||
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
|
||||
case width > oldWidth:
|
||||
// If the terminal expands then our position calculations will
|
||||
// be wrong in the future because we think the cursor is
|
||||
// |t.pos| chars into the string, but there will be a gap at
|
||||
// the end of any wrapped line.
|
||||
//
|
||||
// But the position will actually be correct until we move, so
|
||||
// we can move back to the beginning and repaint everything.
|
||||
t.clearAndRepaintLinePlusNPrevious(t.maxLine)
|
||||
}
|
||||
|
||||
_, err := t.c.Write(t.outBuf)
|
||||
t.outBuf = t.outBuf[:0]
|
||||
return err
|
||||
}
|
||||
|
||||
type pasteIndicatorError struct{}
|
||||
|
||||
func (pasteIndicatorError) Error() string {
|
||||
return "terminal: ErrPasteIndicator not correctly handled"
|
||||
}
|
||||
|
||||
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
|
||||
// to valid line data. It indicates that bracketed paste mode is enabled and
|
||||
// that the returned line consists only of pasted data. Programs may wish to
|
||||
// interpret pasted data more literally than typed data.
|
||||
var ErrPasteIndicator = pasteIndicatorError{}
|
||||
|
||||
// SetBracketedPasteMode requests that the terminal bracket paste operations
|
||||
// with markers. Not all terminals support this but, if it is supported, then
|
||||
// enabling this mode will stop any autocomplete callback from running due to
|
||||
// pastes. Additionally, any lines that are completely pasted will be returned
|
||||
// from ReadLine with the error set to ErrPasteIndicator.
|
||||
func (t *Terminal) SetBracketedPasteMode(on bool) {
|
||||
if on {
|
||||
io.WriteString(t.c, "\x1b[?2004h")
|
||||
} else {
|
||||
io.WriteString(t.c, "\x1b[?2004l")
|
||||
}
|
||||
}
|
||||
|
||||
// stRingBuffer is a ring buffer of strings.
|
||||
type stRingBuffer struct {
|
||||
// entries contains max elements.
|
||||
entries []string
|
||||
max int
|
||||
// head contains the index of the element most recently added to the ring.
|
||||
head int
|
||||
// size contains the number of elements in the ring.
|
||||
size int
|
||||
}
|
||||
|
||||
func (s *stRingBuffer) Add(a string) {
|
||||
if s.entries == nil {
|
||||
const defaultNumEntries = 100
|
||||
s.entries = make([]string, defaultNumEntries)
|
||||
s.max = defaultNumEntries
|
||||
}
|
||||
|
||||
s.head = (s.head + 1) % s.max
|
||||
s.entries[s.head] = a
|
||||
if s.size < s.max {
|
||||
s.size++
|
||||
}
|
||||
}
|
||||
|
||||
// NthPreviousEntry returns the value passed to the nth previous call to Add.
|
||||
// If n is zero then the immediately prior value is returned, if one, then the
|
||||
// next most recent, and so on. If such an element doesn't exist then ok is
|
||||
// false.
|
||||
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
|
||||
if n >= s.size {
|
||||
return "", false
|
||||
}
|
||||
index := s.head - n
|
||||
if index < 0 {
|
||||
index += s.max
|
||||
}
|
||||
return s.entries[index], true
|
||||
}
|
269
vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
generated
vendored
Normal file
269
vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
generated
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
// Copyright 2011 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 terminal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type MockTerminal struct {
|
||||
toSend []byte
|
||||
bytesPerRead int
|
||||
received []byte
|
||||
}
|
||||
|
||||
func (c *MockTerminal) Read(data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
if n > len(c.toSend) {
|
||||
n = len(c.toSend)
|
||||
}
|
||||
if n == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if c.bytesPerRead > 0 && n > c.bytesPerRead {
|
||||
n = c.bytesPerRead
|
||||
}
|
||||
copy(data, c.toSend[:n])
|
||||
c.toSend = c.toSend[n:]
|
||||
return
|
||||
}
|
||||
|
||||
func (c *MockTerminal) Write(data []byte) (n int, err error) {
|
||||
c.received = append(c.received, data...)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
c := &MockTerminal{}
|
||||
ss := NewTerminal(c, "> ")
|
||||
line, err := ss.ReadLine()
|
||||
if line != "" {
|
||||
t.Errorf("Expected empty line but got: %s", line)
|
||||
}
|
||||
if err != io.EOF {
|
||||
t.Errorf("Error should have been EOF but got: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
var keyPressTests = []struct {
|
||||
in string
|
||||
line string
|
||||
err error
|
||||
throwAwayLines int
|
||||
}{
|
||||
{
|
||||
err: io.EOF,
|
||||
},
|
||||
{
|
||||
in: "\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "foo\r",
|
||||
line: "foo",
|
||||
},
|
||||
{
|
||||
in: "a\x1b[Cb\r", // right
|
||||
line: "ab",
|
||||
},
|
||||
{
|
||||
in: "a\x1b[Db\r", // left
|
||||
line: "ba",
|
||||
},
|
||||
{
|
||||
in: "a\177b\r", // backspace
|
||||
line: "b",
|
||||
},
|
||||
{
|
||||
in: "\x1b[A\r", // up
|
||||
},
|
||||
{
|
||||
in: "\x1b[B\r", // down
|
||||
},
|
||||
{
|
||||
in: "line\x1b[A\x1b[B\r", // up then down
|
||||
line: "line",
|
||||
},
|
||||
{
|
||||
in: "line1\rline2\x1b[A\r", // recall previous line.
|
||||
line: "line1",
|
||||
throwAwayLines: 1,
|
||||
},
|
||||
{
|
||||
// recall two previous lines and append.
|
||||
in: "line1\rline2\rline3\x1b[A\x1b[Axxx\r",
|
||||
line: "line1xxx",
|
||||
throwAwayLines: 2,
|
||||
},
|
||||
{
|
||||
// Ctrl-A to move to beginning of line followed by ^K to kill
|
||||
// line.
|
||||
in: "a b \001\013\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
// Ctrl-A to move to beginning of line, Ctrl-E to move to end,
|
||||
// finally ^K to kill nothing.
|
||||
in: "a b \001\005\013\r",
|
||||
line: "a b ",
|
||||
},
|
||||
{
|
||||
in: "\027\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a\027\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a \027\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a b\027\r",
|
||||
line: "a ",
|
||||
},
|
||||
{
|
||||
in: "a b \027\r",
|
||||
line: "a ",
|
||||
},
|
||||
{
|
||||
in: "one two thr\x1b[D\027\r",
|
||||
line: "one two r",
|
||||
},
|
||||
{
|
||||
in: "\013\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
in: "a\013\r",
|
||||
line: "a",
|
||||
},
|
||||
{
|
||||
in: "ab\x1b[D\013\r",
|
||||
line: "a",
|
||||
},
|
||||
{
|
||||
in: "Ξεσκεπάζω\r",
|
||||
line: "Ξεσκεπάζω",
|
||||
},
|
||||
{
|
||||
in: "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace.
|
||||
line: "",
|
||||
throwAwayLines: 1,
|
||||
},
|
||||
{
|
||||
in: "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter.
|
||||
line: "£",
|
||||
throwAwayLines: 1,
|
||||
},
|
||||
{
|
||||
// Ctrl-D at the end of the line should be ignored.
|
||||
in: "a\004\r",
|
||||
line: "a",
|
||||
},
|
||||
{
|
||||
// a, b, left, Ctrl-D should erase the b.
|
||||
in: "ab\x1b[D\004\r",
|
||||
line: "a",
|
||||
},
|
||||
{
|
||||
// a, b, c, d, left, left, ^U should erase to the beginning of
|
||||
// the line.
|
||||
in: "abcd\x1b[D\x1b[D\025\r",
|
||||
line: "cd",
|
||||
},
|
||||
{
|
||||
// Bracketed paste mode: control sequences should be returned
|
||||
// verbatim in paste mode.
|
||||
in: "abc\x1b[200~de\177f\x1b[201~\177\r",
|
||||
line: "abcde\177",
|
||||
},
|
||||
{
|
||||
// Enter in bracketed paste mode should still work.
|
||||
in: "abc\x1b[200~d\refg\x1b[201~h\r",
|
||||
line: "efgh",
|
||||
throwAwayLines: 1,
|
||||
},
|
||||
{
|
||||
// Lines consisting entirely of pasted data should be indicated as such.
|
||||
in: "\x1b[200~a\r",
|
||||
line: "a",
|
||||
err: ErrPasteIndicator,
|
||||
},
|
||||
}
|
||||
|
||||
func TestKeyPresses(t *testing.T) {
|
||||
for i, test := range keyPressTests {
|
||||
for j := 1; j < len(test.in); j++ {
|
||||
c := &MockTerminal{
|
||||
toSend: []byte(test.in),
|
||||
bytesPerRead: j,
|
||||
}
|
||||
ss := NewTerminal(c, "> ")
|
||||
for k := 0; k < test.throwAwayLines; k++ {
|
||||
_, err := ss.ReadLine()
|
||||
if err != nil {
|
||||
t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err)
|
||||
}
|
||||
}
|
||||
line, err := ss.ReadLine()
|
||||
if line != test.line {
|
||||
t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line)
|
||||
break
|
||||
}
|
||||
if err != test.err {
|
||||
t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPasswordNotSaved(t *testing.T) {
|
||||
c := &MockTerminal{
|
||||
toSend: []byte("password\r\x1b[A\r"),
|
||||
bytesPerRead: 1,
|
||||
}
|
||||
ss := NewTerminal(c, "> ")
|
||||
pw, _ := ss.ReadPassword("> ")
|
||||
if pw != "password" {
|
||||
t.Fatalf("failed to read password, got %s", pw)
|
||||
}
|
||||
line, _ := ss.ReadLine()
|
||||
if len(line) > 0 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
128
vendor/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
Normal file
128
vendor/golang.org/x/crypto/ssh/terminal/util.go
generated
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2011 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 darwin dragonfly freebsd linux,!appengine netbsd openbsd
|
||||
|
||||
// Package terminal provides support functions for dealing with terminals, as
|
||||
// commonly found on UNIX systems.
|
||||
//
|
||||
// Putting a terminal into raw mode is the most common requirement:
|
||||
//
|
||||
// oldState, err := terminal.MakeRaw(0)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// defer terminal.Restore(0, oldState)
|
||||
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// State contains the state of a terminal.
|
||||
type State struct {
|
||||
termios syscall.Termios
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
var termios syscall.Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
|
||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
func MakeRaw(fd int) (*State, error) {
|
||||
var oldState State
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newState := oldState.termios
|
||||
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
|
||||
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
// GetState returns the current state of a terminal which may be useful to
|
||||
// restore the terminal after a signal.
|
||||
func GetState(fd int) (*State, error) {
|
||||
var oldState State
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
func Restore(fd int, state *State) error {
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
var dimensions [4]uint16
|
||||
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
|
||||
return -1, -1, err
|
||||
}
|
||||
return int(dimensions[1]), int(dimensions[0]), nil
|
||||
}
|
||||
|
||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
// returned does not include the \n.
|
||||
func ReadPassword(fd int) ([]byte, error) {
|
||||
var oldState syscall.Termios
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newState := oldState
|
||||
newState.Lflag &^= syscall.ECHO
|
||||
newState.Lflag |= syscall.ICANON | syscall.ISIG
|
||||
newState.Iflag |= syscall.ICRNL
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
|
||||
}()
|
||||
|
||||
var buf [16]byte
|
||||
var ret []byte
|
||||
for {
|
||||
n, err := syscall.Read(fd, buf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
if len(ret) == 0 {
|
||||
return nil, io.EOF
|
||||
}
|
||||
break
|
||||
}
|
||||
if buf[n-1] == '\n' {
|
||||
n--
|
||||
}
|
||||
ret = append(ret, buf[:n]...)
|
||||
if n < len(buf) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
12
vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
generated
vendored
Normal file
12
vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2013 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 darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package terminal
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
const ioctlWriteTermios = syscall.TIOCSETA
|
11
vendor/golang.org/x/crypto/ssh/terminal/util_linux.go
generated
vendored
Normal file
11
vendor/golang.org/x/crypto/ssh/terminal/util_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2013 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 terminal
|
||||
|
||||
// These constants are declared here, rather than importing
|
||||
// them from the syscall package as some syscall packages, even
|
||||
// on linux, for example gccgo, do not declare them.
|
||||
const ioctlReadTermios = 0x5401 // syscall.TCGETS
|
||||
const ioctlWriteTermios = 0x5402 // syscall.TCSETS
|
174
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
generated
vendored
Normal file
174
vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
// Copyright 2011 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 windows
|
||||
|
||||
// Package terminal provides support functions for dealing with terminals, as
|
||||
// commonly found on UNIX systems.
|
||||
//
|
||||
// Putting a terminal into raw mode is the most common requirement:
|
||||
//
|
||||
// oldState, err := terminal.MakeRaw(0)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// defer terminal.Restore(0, oldState)
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
enableLineInput = 2
|
||||
enableEchoInput = 4
|
||||
enableProcessedInput = 1
|
||||
enableWindowInput = 8
|
||||
enableMouseInput = 16
|
||||
enableInsertMode = 32
|
||||
enableQuickEditMode = 64
|
||||
enableExtendedFlags = 128
|
||||
enableAutoPosition = 256
|
||||
enableProcessedOutput = 1
|
||||
enableWrapAtEolOutput = 2
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
||||
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
)
|
||||
|
||||
type (
|
||||
short int16
|
||||
word uint16
|
||||
|
||||
coord struct {
|
||||
x short
|
||||
y short
|
||||
}
|
||||
smallRect struct {
|
||||
left short
|
||||
top short
|
||||
right short
|
||||
bottom short
|
||||
}
|
||||
consoleScreenBufferInfo struct {
|
||||
size coord
|
||||
cursorPosition coord
|
||||
attributes word
|
||||
window smallRect
|
||||
maximumWindowSize coord
|
||||
}
|
||||
)
|
||||
|
||||
type State struct {
|
||||
mode uint32
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd int) bool {
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
||||
|
||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
func MakeRaw(fd int) (*State, error) {
|
||||
var st uint32
|
||||
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||
if e != 0 {
|
||||
return nil, error(e)
|
||||
}
|
||||
st &^= (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
|
||||
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
|
||||
if e != 0 {
|
||||
return nil, error(e)
|
||||
}
|
||||
return &State{st}, nil
|
||||
}
|
||||
|
||||
// GetState returns the current state of a terminal which may be useful to
|
||||
// restore the terminal after a signal.
|
||||
func GetState(fd int) (*State, error) {
|
||||
var st uint32
|
||||
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||
if e != 0 {
|
||||
return nil, error(e)
|
||||
}
|
||||
return &State{st}, nil
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
func Restore(fd int, state *State) error {
|
||||
_, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
var info consoleScreenBufferInfo
|
||||
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
|
||||
if e != 0 {
|
||||
return 0, 0, error(e)
|
||||
}
|
||||
return int(info.size.x), int(info.size.y), nil
|
||||
}
|
||||
|
||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
// returned does not include the \n.
|
||||
func ReadPassword(fd int) ([]byte, error) {
|
||||
var st uint32
|
||||
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||
if e != 0 {
|
||||
return nil, error(e)
|
||||
}
|
||||
old := st
|
||||
|
||||
st &^= (enableEchoInput)
|
||||
st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
|
||||
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
|
||||
if e != 0 {
|
||||
return nil, error(e)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
|
||||
}()
|
||||
|
||||
var buf [16]byte
|
||||
var ret []byte
|
||||
for {
|
||||
n, err := syscall.Read(syscall.Handle(fd), buf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
if len(ret) == 0 {
|
||||
return nil, io.EOF
|
||||
}
|
||||
break
|
||||
}
|
||||
if buf[n-1] == '\n' {
|
||||
n--
|
||||
}
|
||||
if n > 0 && buf[n-1] == '\r' {
|
||||
n--
|
||||
}
|
||||
ret = append(ret, buf[:n]...)
|
||||
if n < len(buf) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue