vendor: update all dependencies

This commit is contained in:
Nick Craig-Wood 2018-06-17 17:59:12 +01:00
parent 3f0789e2db
commit 08021c4636
2474 changed files with 435818 additions and 282709 deletions

View file

@ -14,7 +14,6 @@
package acme
import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
@ -23,6 +22,8 @@ import (
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/hex"
"encoding/json"
@ -33,7 +34,6 @@ import (
"io/ioutil"
"math/big"
"net/http"
"strconv"
"strings"
"sync"
"time"
@ -42,6 +42,9 @@ import (
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge.
var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
const (
maxChainLen = 5 // max depth and breadth of a certificate chain
maxCertSize = 1 << 20 // max size of a certificate, in bytes
@ -76,6 +79,22 @@ type Client struct {
// will have no effect.
DirectoryURL string
// RetryBackoff computes the duration after which the nth retry of a failed request
// should occur. The value of n for the first call on failure is 1.
// The values of r and resp are the request and response of the last failed attempt.
// If the returned value is negative or zero, no more retries are done and an error
// is returned to the caller of the original method.
//
// Requests which result in a 4xx client error are not retried,
// except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests.
//
// If RetryBackoff is nil, a truncated exponential backoff algorithm
// with the ceiling of 10 seconds is used, where each subsequent retry n
// is done after either ("Retry-After" + jitter) or (2^n seconds + jitter),
// preferring the former if "Retry-After" header is found in the resp.
// The jitter is a random value up to 1 second.
RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration
dirMu sync.Mutex // guards writes to dir
dir *Directory // cached result of Client's Discover method
@ -99,15 +118,12 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
if dirURL == "" {
dirURL = LetsEncryptURL
}
res, err := c.get(ctx, dirURL)
res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK))
if err != nil {
return Directory{}, err
}
defer res.Body.Close()
c.addNonce(res.Header)
if res.StatusCode != http.StatusOK {
return Directory{}, responseError(res)
}
var v struct {
Reg string `json:"new-reg"`
@ -166,14 +182,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
req.NotAfter = now.Add(exp).Format(time.RFC3339)
}
res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req)
res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, "", err
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
return nil, "", responseError(res)
}
curl := res.Header.Get("Location") // cert permanent URL
if res.ContentLength == 0 {
@ -196,26 +209,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
// Callers are encouraged to parse the returned value to ensure the certificate is valid
// and has expected features.
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
for {
res, err := c.get(ctx, url)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode == http.StatusOK {
return c.responseCert(ctx, res, bundle)
}
if res.StatusCode > 299 {
return nil, responseError(res)
}
d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second)
select {
case <-time.After(d):
// retry
case <-ctx.Done():
return nil, ctx.Err()
}
res, err := c.get(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
return c.responseCert(ctx, res, bundle)
}
// RevokeCert revokes a previously issued certificate cert, provided in DER format.
@ -241,14 +239,11 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
if key == nil {
key = c.Key
}
res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body)
res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return responseError(res)
}
return nil
}
@ -329,14 +324,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
Resource: "new-authz",
Identifier: authzID{Type: "dns", Value: domain},
}
res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req)
res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
return nil, responseError(res)
}
var v wireAuthz
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
@ -353,14 +345,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
// If a caller needs to poll an authorization until its status is final,
// see the WaitAuthorization method.
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
res, err := c.get(ctx, url)
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
return nil, responseError(res)
}
var v wireAuthz
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
@ -387,14 +376,11 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
Status: "deactivated",
Delete: true,
}
res, err := c.retryPostJWS(ctx, c.Key, url, req)
res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return responseError(res)
}
return nil
}
@ -406,44 +392,42 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
// In all other cases WaitAuthorization returns an error.
// If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
sleep := sleeper(ctx)
for {
res, err := c.get(ctx, url)
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
if res.StatusCode >= 400 && res.StatusCode <= 499 {
// Non-retriable error. For instance, Let's Encrypt may return 404 Not Found
// when requesting an expired authorization.
defer res.Body.Close()
return nil, responseError(res)
}
retry := res.Header.Get("Retry-After")
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
res.Body.Close()
if err := sleep(retry, 1); err != nil {
return nil, err
}
continue
}
var raw wireAuthz
err = json.NewDecoder(res.Body).Decode(&raw)
res.Body.Close()
if err != nil {
if err := sleep(retry, 0); err != nil {
return nil, err
}
continue
}
if raw.Status == StatusValid {
switch {
case err != nil:
// Skip and retry.
case raw.Status == StatusValid:
return raw.authorization(url), nil
}
if raw.Status == StatusInvalid {
case raw.Status == StatusInvalid:
return nil, raw.error(url)
}
if err := sleep(retry, 0); err != nil {
return nil, err
// Exponential backoff is implemented in c.get above.
// This is just to prevent continuously hitting the CA
// while waiting for a final authorization status.
d := retryAfter(res.Header.Get("Retry-After"))
if d == 0 {
// Given that the fastest challenges TLS-SNI and HTTP-01
// require a CA to make at least 1 network round trip
// and most likely persist a challenge state,
// this default delay seems reasonable.
d = time.Second
}
t := time.NewTimer(d)
select {
case <-ctx.Done():
t.Stop()
return nil, ctx.Err()
case <-t.C:
// Retry.
}
}
}
@ -452,14 +436,11 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
//
// A client typically polls a challenge status using this method.
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
res, err := c.get(ctx, url)
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
return nil, responseError(res)
}
v := wireChallenge{URI: url}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
@ -486,16 +467,14 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error
Type: chal.Type,
Auth: auth,
}
res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req)
res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus(
http.StatusOK, // according to the spec
http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
))
if err != nil {
return nil, err
}
defer res.Body.Close()
// Note: the protocol specifies 200 as the expected response code, but
// letsencrypt seems to be returning 202.
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
return nil, responseError(res)
}
var v wireChallenge
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
@ -552,7 +531,7 @@ func (c *Client) HTTP01ChallengePath(token string) string {
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
//
// The returned certificate is valid for the next 24 hours and must be presented only when
// the server name of the client hello matches exactly the returned name value.
// the server name of the TLS ClientHello matches exactly the returned name value.
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
ka, err := keyAuth(c.Key.Public(), token)
if err != nil {
@ -579,7 +558,7 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
//
// The returned certificate is valid for the next 24 hours and must be presented only when
// the server name in the client hello matches exactly the returned name value.
// the server name in the TLS ClientHello matches exactly the returned name value.
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
b := sha256.Sum256([]byte(token))
h := hex.EncodeToString(b[:])
@ -600,6 +579,52 @@ func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tl
return cert, sanA, nil
}
// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response.
// Servers can present the certificate to validate the challenge and prove control
// over a domain name. For more details on TLS-ALPN-01 see
// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3
//
// The token argument is a Challenge.Token value.
// If a WithKey option is provided, its private part signs the returned cert,
// and the public part is used to specify the signee.
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
//
// The returned certificate is valid for the next 24 hours and must be presented only when
// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol
// has been specified.
func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) {
ka, err := keyAuth(c.Key.Public(), token)
if err != nil {
return tls.Certificate{}, err
}
shasum := sha256.Sum256([]byte(ka))
extValue, err := asn1.Marshal(shasum[:])
if err != nil {
return tls.Certificate{}, err
}
acmeExtension := pkix.Extension{
Id: idPeACMEIdentifierV1,
Critical: true,
Value: extValue,
}
tmpl := defaultTLSChallengeCertTemplate()
var newOpt []CertOption
for _, o := range opt {
switch o := o.(type) {
case *certOptTemplate:
t := *(*x509.Certificate)(o) // shallow copy is ok
tmpl = &t
default:
newOpt = append(newOpt, o)
}
}
tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension)
newOpt = append(newOpt, WithTemplate(tmpl))
return tlsChallengeCert([]string{domain}, newOpt)
}
// doReg sends all types of registration requests.
// The type of request is identified by typ argument, which is a "resource"
// in the ACME spec terms.
@ -619,14 +644,14 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
req.Contact = acct.Contact
req.Agreement = acct.AgreedTerms
}
res, err := c.retryPostJWS(ctx, c.Key, url, req)
res, err := c.post(ctx, c.Key, url, req, wantStatus(
http.StatusOK, // updates and deletes
http.StatusCreated, // new account creation
))
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode > 299 {
return nil, responseError(res)
}
var v struct {
Contact []string
@ -656,59 +681,6 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
}, nil
}
// retryPostJWS will retry calls to postJWS if there is a badNonce error,
// clearing the stored nonces after each error.
// If the response was 4XX-5XX, then responseError is called on the body,
// the body is closed, and the error returned.
func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
sleep := sleeper(ctx)
for {
res, err := c.postJWS(ctx, key, url, body)
if err != nil {
return nil, err
}
// handle errors 4XX-5XX with responseError
if res.StatusCode >= 400 && res.StatusCode <= 599 {
err := responseError(res)
res.Body.Close()
// according to spec badNonce is urn:ietf:params:acme:error:badNonce
// however, acme servers in the wild return their version of the error
// https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") {
// clear any nonces that we might've stored that might now be
// considered bad
c.clearNonces()
retry := res.Header.Get("Retry-After")
if err := sleep(retry, 1); err != nil {
return nil, err
}
continue
}
return nil, err
}
return res, nil
}
}
// postJWS signs the body with the given key and POSTs it to the provided url.
// The body argument must be JSON-serializable.
func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
nonce, err := c.popNonce(ctx, url)
if err != nil {
return nil, err
}
b, err := jwsEncodeJSON(body, key, nonce)
if err != nil {
return nil, err
}
res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b))
if err != nil {
return nil, err
}
c.addNonce(res.Header)
return res, nil
}
// popNonce returns a nonce value previously stored with c.addNonce
// or fetches a fresh one from the given URL.
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
@ -749,58 +721,12 @@ func (c *Client) addNonce(h http.Header) {
c.nonces[v] = struct{}{}
}
func (c *Client) httpClient() *http.Client {
if c.HTTPClient != nil {
return c.HTTPClient
}
return http.DefaultClient
}
func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) {
req, err := http.NewRequest("GET", urlStr, nil)
if err != nil {
return nil, err
}
return c.do(ctx, req)
}
func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) {
req, err := http.NewRequest("HEAD", urlStr, nil)
if err != nil {
return nil, err
}
return c.do(ctx, req)
}
func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest("POST", urlStr, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
return c.do(ctx, req)
}
func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
res, err := c.httpClient().Do(req.WithContext(ctx))
if err != nil {
select {
case <-ctx.Done():
// Prefer the unadorned context error.
// (The acme package had tests assuming this, previously from ctxhttp's
// behavior, predating net/http supporting contexts natively)
// TODO(bradfitz): reconsider this in the future. But for now this
// requires no test updates.
return nil, ctx.Err()
default:
return nil, err
}
}
return res, nil
}
func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
resp, err := c.head(ctx, url)
r, err := http.NewRequest("HEAD", url, nil)
if err != nil {
return "", err
}
resp, err := c.doNoRetry(ctx, r)
if err != nil {
return "", err
}
@ -852,24 +778,6 @@ func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bo
return cert, nil
}
// responseError creates an error of Error type from resp.
func responseError(resp *http.Response) error {
// don't care if ReadAll returns an error:
// json.Unmarshal will fail in that case anyway
b, _ := ioutil.ReadAll(resp.Body)
e := &wireError{Status: resp.StatusCode}
if err := json.Unmarshal(b, e); err != nil {
// this is not a regular error response:
// populate detail with anything we received,
// e.Status will already contain HTTP response code value
e.Detail = string(b)
if e.Detail == "" {
e.Detail = resp.Status
}
}
return e.error(resp.Header)
}
// chainCert fetches CA certificate chain recursively by following "up" links.
// Each recursive call increments the depth by 1, resulting in an error
// if the recursion level reaches maxChainLen.
@ -880,14 +788,11 @@ func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte
return nil, errors.New("acme: certificate chain is too deep")
}
res, err := c.get(ctx, url)
res, err := c.get(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, responseError(res)
}
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
if err != nil {
return nil, err
@ -932,65 +837,6 @@ func linkHeader(h http.Header, rel string) []string {
return links
}
// sleeper returns a function that accepts the Retry-After HTTP header value
// and an increment that's used with backoff to increasingly sleep on
// consecutive calls until the context is done. If the Retry-After header
// cannot be parsed, then backoff is used with a maximum sleep time of 10
// seconds.
func sleeper(ctx context.Context) func(ra string, inc int) error {
var count int
return func(ra string, inc int) error {
count += inc
d := backoff(count, 10*time.Second)
d = retryAfter(ra, d)
wakeup := time.NewTimer(d)
defer wakeup.Stop()
select {
case <-ctx.Done():
return ctx.Err()
case <-wakeup.C:
return nil
}
}
}
// retryAfter parses a Retry-After HTTP header value,
// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
// It returns d if v cannot be parsed.
func retryAfter(v string, d time.Duration) time.Duration {
if i, err := strconv.Atoi(v); err == nil {
return time.Duration(i) * time.Second
}
t, err := http.ParseTime(v)
if err != nil {
return d
}
return t.Sub(timeNow())
}
// backoff computes a duration after which an n+1 retry iteration should occur
// using truncated exponential backoff algorithm.
//
// The n argument is always bounded between 0 and 30.
// The max argument defines upper bound for the returned value.
func backoff(n int, max time.Duration) time.Duration {
if n < 0 {
n = 0
}
if n > 30 {
n = 30
}
var d time.Duration
if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
d = time.Duration(x.Int64()) * time.Millisecond
}
d += time.Duration(1<<uint(n)) * time.Second
if d > max {
return max
}
return d
}
// keyAuth generates a key authorization string for a given token.
func keyAuth(pub crypto.PublicKey, token string) (string, error) {
th, err := JWKThumbprint(pub)
@ -1000,15 +846,25 @@ func keyAuth(pub crypto.PublicKey, token string) (string, error) {
return fmt.Sprintf("%s.%s", token, th), nil
}
// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges.
func defaultTLSChallengeCertTemplate() *x509.Certificate {
return &x509.Certificate{
SerialNumber: big.NewInt(1),
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
}
// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges
// with the given SANs and auto-generated public/private key pair.
// The Subject Common Name is set to the first SAN to aid debugging.
// To create a cert with a custom key pair, specify WithKey option.
func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
var (
key crypto.Signer
tmpl *x509.Certificate
)
var key crypto.Signer
tmpl := defaultTLSChallengeCertTemplate()
for _, o := range opt {
switch o := o.(type) {
case *certOptKey:
@ -1017,7 +873,7 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
}
key = o.key
case *certOptTemplate:
var t = *(*x509.Certificate)(o) // shallow copy is ok
t := *(*x509.Certificate)(o) // shallow copy is ok
tmpl = &t
default:
// package's fault, if we let this happen:
@ -1030,16 +886,6 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
return tls.Certificate{}, err
}
}
if tmpl == nil {
tmpl = &x509.Certificate{
SerialNumber: big.NewInt(1),
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
}
tmpl.DNSNames = san
if len(san) > 0 {
tmpl.Subject.CommonName = san[0]

View file

@ -13,9 +13,9 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"net/http/httptest"
@ -485,88 +485,37 @@ func TestGetAuthorization(t *testing.T) {
}
func TestWaitAuthorization(t *testing.T) {
var count int
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
w.Header().Set("Retry-After", "0")
if count > 1 {
fmt.Fprintf(w, `{"status":"valid"}`)
return
t.Run("wait loop", func(t *testing.T) {
var count int
authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
count++
w.Header().Set("Retry-After", "0")
if count > 1 {
fmt.Fprintf(w, `{"status":"valid"}`)
return
}
fmt.Fprintf(w, `{"status":"pending"}`)
})
if err != nil {
t.Fatalf("non-nil error: %v", err)
}
fmt.Fprintf(w, `{"status":"pending"}`)
}))
defer ts.Close()
type res struct {
authz *Authorization
err error
}
done := make(chan res)
defer close(done)
go func() {
var client Client
a, err := client.WaitAuthorization(context.Background(), ts.URL)
done <- res{a, err}
}()
select {
case <-time.After(5 * time.Second):
t.Fatal("WaitAuthz took too long to return")
case res := <-done:
if res.err != nil {
t.Fatalf("res.err = %v", res.err)
}
if res.authz == nil {
t.Fatal("res.authz is nil")
}
}
}
func TestWaitAuthorizationInvalid(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{"status":"invalid"}`)
}))
defer ts.Close()
res := make(chan error)
defer close(res)
go func() {
var client Client
_, err := client.WaitAuthorization(context.Background(), ts.URL)
res <- err
}()
select {
case <-time.After(3 * time.Second):
t.Fatal("WaitAuthz took too long to return")
case err := <-res:
if err == nil {
t.Error("err is nil")
if authz == nil {
t.Fatal("authz is nil")
}
})
t.Run("invalid status", func(t *testing.T) {
_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{"status":"invalid"}`)
})
if _, ok := err.(*AuthorizationError); !ok {
t.Errorf("err is %T; want *AuthorizationError", err)
t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err)
}
}
}
func TestWaitAuthorizationClientError(t *testing.T) {
const code = http.StatusBadRequest
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(code)
}))
defer ts.Close()
ch := make(chan error, 1)
go func() {
var client Client
_, err := client.WaitAuthorization(context.Background(), ts.URL)
ch <- err
}()
select {
case <-time.After(3 * time.Second):
t.Fatal("WaitAuthz took too long to return")
case err := <-ch:
})
t.Run("non-retriable error", func(t *testing.T) {
const code = http.StatusBadRequest
_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(code)
})
res, ok := err.(*Error)
if !ok {
t.Fatalf("err is %v (%T); want a non-nil *Error", err, err)
@ -574,34 +523,60 @@ func TestWaitAuthorizationClientError(t *testing.T) {
if res.StatusCode != code {
t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code)
}
})
for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} {
t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) {
var count int
authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
count++
w.Header().Set("Retry-After", "0")
if count > 1 {
fmt.Fprintf(w, `{"status":"valid"}`)
return
}
w.WriteHeader(code)
})
if err != nil {
t.Fatalf("non-nil error: %v", err)
}
if authz == nil {
t.Fatal("authz is nil")
}
})
}
}
func TestWaitAuthorizationCancel(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Retry-After", "60")
fmt.Fprintf(w, `{"status":"pending"}`)
}))
defer ts.Close()
res := make(chan error)
defer close(res)
go func() {
var client Client
t.Run("context cancel", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel()
_, err := client.WaitAuthorization(ctx, ts.URL)
res <- err
}()
select {
case <-time.After(time.Second):
t.Fatal("WaitAuthz took too long to return")
case err := <-res:
_, err := runWaitAuthorization(ctx, t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Retry-After", "60")
fmt.Fprintf(w, `{"status":"pending"}`)
})
if err == nil {
t.Error("err is nil")
}
})
}
func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc) (*Authorization, error) {
t.Helper()
ts := httptest.NewServer(h)
defer ts.Close()
type res struct {
authz *Authorization
err error
}
ch := make(chan res, 1)
go func() {
var client Client
a, err := client.WaitAuthorization(ctx, ts.URL)
ch <- res{a, err}
}()
select {
case <-time.After(3 * time.Second):
t.Fatal("WaitAuthorization took too long to return")
case v := <-ch:
return v.authz, v.err
}
panic("runWaitAuthorization: out of select")
}
func TestRevokeAuthorization(t *testing.T) {
@ -628,7 +603,7 @@ func TestRevokeAuthorization(t *testing.T) {
t.Errorf("req.Delete is false")
}
case "/2":
w.WriteHeader(http.StatusInternalServerError)
w.WriteHeader(http.StatusBadRequest)
}
}))
defer ts.Close()
@ -849,7 +824,7 @@ func TestFetchCertRetry(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if count < 1 {
w.Header().Set("Retry-After", "0")
w.WriteHeader(http.StatusAccepted)
w.WriteHeader(http.StatusTooManyRequests)
count++
return
}
@ -1096,44 +1071,6 @@ func TestNonce_postJWS(t *testing.T) {
}
}
func TestRetryPostJWS(t *testing.T) {
var count int
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
if r.Method == "HEAD" {
// We expect the client to do 2 head requests to fetch
// nonces, one to start and another after getting badNonce
return
}
head, err := decodeJWSHead(r)
if err != nil {
t.Errorf("decodeJWSHead: %v", err)
} else if head.Nonce == "" {
t.Error("head.Nonce is empty")
} else if head.Nonce == "nonce1" {
// return a badNonce error to force the call to retry
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`))
return
}
// Make client.Authorize happy; we're not testing its result.
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"status":"valid"}`))
}))
defer ts.Close()
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
// This call will fail with badNonce, causing a retry
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
t.Errorf("client.Authorize 1: %v", err)
}
if count != 4 {
t.Errorf("total requests count: %d; want 4", count)
}
}
func TestLinkHeader(t *testing.T) {
h := http.Header{"Link": {
`<https://example.com/acme/new-authz>;rel="next"`,
@ -1157,37 +1094,6 @@ func TestLinkHeader(t *testing.T) {
}
}
func TestErrorResponse(t *testing.T) {
s := `{
"status": 400,
"type": "urn:acme:error:xxx",
"detail": "text"
}`
res := &http.Response{
StatusCode: 400,
Status: "400 Bad Request",
Body: ioutil.NopCloser(strings.NewReader(s)),
Header: http.Header{"X-Foo": {"bar"}},
}
err := responseError(res)
v, ok := err.(*Error)
if !ok {
t.Fatalf("err = %+v (%T); want *Error type", err, err)
}
if v.StatusCode != 400 {
t.Errorf("v.StatusCode = %v; want 400", v.StatusCode)
}
if v.ProblemType != "urn:acme:error:xxx" {
t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType)
}
if v.Detail != "text" {
t.Errorf("v.Detail = %q; want text", v.Detail)
}
if !reflect.DeepEqual(v.Header, res.Header) {
t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header)
}
}
func TestTLSSNI01ChallengeCert(t *testing.T) {
const (
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
@ -1255,6 +1161,58 @@ func TestTLSSNI02ChallengeCert(t *testing.T) {
}
}
func TestTLSALPN01ChallengeCert(t *testing.T) {
const (
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA." + testKeyECThumbprint
// echo -n <token.testKeyECThumbprint> | shasum -a 256
h = "0420dbbd5eefe7b4d06eb9d1d9f5acb4c7cda27d320e4b30332f0b6cb441734ad7b0"
domain = "example.com"
)
extValue, err := hex.DecodeString(h)
if err != nil {
t.Fatal(err)
}
client := &Client{Key: testKeyEC}
tlscert, err := client.TLSALPN01ChallengeCert(token, domain)
if err != nil {
t.Fatal(err)
}
if n := len(tlscert.Certificate); n != 1 {
t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
}
cert, err := x509.ParseCertificate(tlscert.Certificate[0])
if err != nil {
t.Fatal(err)
}
names := []string{domain}
if !reflect.DeepEqual(cert.DNSNames, names) {
t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
}
if cn := cert.Subject.CommonName; cn != domain {
t.Errorf("CommonName = %q; want %q", cn, domain)
}
acmeExts := []pkix.Extension{}
for _, ext := range cert.Extensions {
if idPeACMEIdentifierV1.Equal(ext.Id) {
acmeExts = append(acmeExts, ext)
}
}
if len(acmeExts) != 1 {
t.Errorf("acmeExts = %v; want exactly one", acmeExts)
}
if !acmeExts[0].Critical {
t.Errorf("acmeExt.Critical = %v; want true", acmeExts[0].Critical)
}
if bytes.Compare(acmeExts[0].Value, extValue) != 0 {
t.Errorf("acmeExt.Value = %v; want %v", acmeExts[0].Value, extValue)
}
}
func TestTLSChallengeCertOpt(t *testing.T) {
key, err := rsa.GenerateKey(rand.Reader, 512)
if err != nil {
@ -1353,28 +1311,3 @@ func TestDNS01ChallengeRecord(t *testing.T) {
t.Errorf("val = %q; want %q", val, value)
}
}
func TestBackoff(t *testing.T) {
tt := []struct{ min, max time.Duration }{
{time.Second, 2 * time.Second},
{2 * time.Second, 3 * time.Second},
{4 * time.Second, 5 * time.Second},
{8 * time.Second, 9 * time.Second},
}
for i, test := range tt {
d := backoff(i, time.Minute)
if d < test.min || test.max < d {
t.Errorf("%d: d = %v; want between %v and %v", i, d, test.min, test.max)
}
}
min, max := time.Second, 2*time.Second
if d := backoff(-1, time.Minute); d < min || max < d {
t.Errorf("d = %v; want between %v and %v", d, min, max)
}
bound := 10 * time.Second
if d := backoff(100, bound); d != bound {
t.Errorf("d = %v; want %v", d, bound)
}
}

View file

@ -98,11 +98,11 @@ type Manager struct {
// To always accept the terms, the callers can use AcceptTOS.
Prompt func(tosURL string) bool
// Cache optionally stores and retrieves previously-obtained certificates.
// If nil, certs will only be cached for the lifetime of the Manager.
// Cache optionally stores and retrieves previously-obtained certificates
// and other state. If nil, certs will only be cached for the lifetime of
// the Manager. Multiple Managers can share the same Cache.
//
// Manager passes the Cache certificates data encoded in PEM, with private/public
// parts combined in a single Cache.Put call, private key first.
// Using a persistent Cache, such as DirCache, is strongly recommended.
Cache Cache
// HostPolicy controls which domains the Manager will attempt
@ -127,8 +127,10 @@ type Manager struct {
// Client is used to perform low-level operations, such as account registration
// and requesting new certificates.
//
// If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
// directory endpoint and a newly-generated ECDSA P-256 key.
// as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is
// generated and, if Cache is not nil, stored in cache.
//
// Mutating the field after the first call of GetCertificate method will have no effect.
Client *acme.Client
@ -140,22 +142,30 @@ type Manager struct {
// If the Client's account key is already registered, Email is not used.
Email string
// ForceRSA makes the Manager generate certificates with 2048-bit RSA keys.
// ForceRSA used to make the Manager generate RSA certificates. It is now ignored.
//
// If false, a default is used. Currently the default
// is EC-based keys using the P-256 curve.
// Deprecated: the Manager will request the correct type of certificate based
// on what each client supports.
ForceRSA bool
// ExtraExtensions are used when generating a new CSR (Certificate Request),
// thus allowing customization of the resulting certificate.
// For instance, TLS Feature Extension (RFC 7633) can be used
// to prevent an OCSP downgrade attack.
//
// The field value is passed to crypto/x509.CreateCertificateRequest
// in the template's ExtraExtensions field as is.
ExtraExtensions []pkix.Extension
clientMu sync.Mutex
client *acme.Client // initialized by acmeClient method
stateMu sync.Mutex
state map[string]*certState // keyed by domain name
state map[certKey]*certState
// renewal tracks the set of domains currently running renewal timers.
// It is keyed by domain name.
renewalMu sync.Mutex
renewal map[string]*domainRenewal
renewal map[certKey]*domainRenewal
// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
tokensMu sync.RWMutex
@ -174,6 +184,23 @@ type Manager struct {
certTokens map[string]*tls.Certificate
}
// certKey is the key by which certificates are tracked in state, renewal and cache.
type certKey struct {
domain string // without trailing dot
isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA)
isToken bool // tls-sni challenge token cert; key type is undefined regardless of isRSA
}
func (c certKey) String() string {
if c.isToken {
return c.domain + "+token"
}
if c.isRSA {
return c.domain + "+rsa"
}
return c.domain
}
// GetCertificate implements the tls.Config.GetCertificate hook.
// It provides a TLS certificate for hello.ServerName host, including answering
// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored.
@ -194,7 +221,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
if !strings.Contains(strings.Trim(name, "."), ".") {
return nil, errors.New("acme/autocert: server name component count invalid")
}
if strings.ContainsAny(name, `/\`) {
if strings.ContainsAny(name, `+/\`) {
return nil, errors.New("acme/autocert: server name contains invalid character")
}
@ -210,7 +237,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
if cert := m.certTokens[name]; cert != nil {
return cert, nil
}
if cert, err := m.cacheGet(ctx, name); err == nil {
if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil {
return cert, nil
}
// TODO: cache error results?
@ -218,8 +245,11 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
}
// regular domain
name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
cert, err := m.cert(ctx, name)
ck := certKey{
domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114
isRSA: !supportsECDSA(hello),
}
cert, err := m.cert(ctx, ck)
if err == nil {
return cert, nil
}
@ -231,14 +261,60 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
if err := m.hostPolicy()(ctx, name); err != nil {
return nil, err
}
cert, err = m.createCert(ctx, name)
cert, err = m.createCert(ctx, ck)
if err != nil {
return nil, err
}
m.cachePut(ctx, name, cert)
m.cachePut(ctx, ck, cert)
return cert, nil
}
func supportsECDSA(hello *tls.ClientHelloInfo) bool {
// The "signature_algorithms" extension, if present, limits the key exchange
// algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1.
if hello.SignatureSchemes != nil {
ecdsaOK := false
schemeLoop:
for _, scheme := range hello.SignatureSchemes {
const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10
switch scheme {
case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256,
tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512:
ecdsaOK = true
break schemeLoop
}
}
if !ecdsaOK {
return false
}
}
if hello.SupportedCurves != nil {
ecdsaOK := false
for _, curve := range hello.SupportedCurves {
if curve == tls.CurveP256 {
ecdsaOK = true
break
}
}
if !ecdsaOK {
return false
}
}
for _, suite := range hello.CipherSuites {
switch suite {
case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
return true
}
}
return false
}
// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
// It returns an http.Handler that responds to the challenges and must be
// running on port 80. If it receives a request that is not an ACME challenge,
@ -304,16 +380,16 @@ func stripPort(hostport string) string {
// cert returns an existing certificate either from m.state or cache.
// If a certificate is found in cache but not in m.state, the latter will be filled
// with the cached value.
func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, error) {
func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
m.stateMu.Lock()
if s, ok := m.state[name]; ok {
if s, ok := m.state[ck]; ok {
m.stateMu.Unlock()
s.RLock()
defer s.RUnlock()
return s.tlscert()
}
defer m.stateMu.Unlock()
cert, err := m.cacheGet(ctx, name)
cert, err := m.cacheGet(ctx, ck)
if err != nil {
return nil, err
}
@ -322,25 +398,25 @@ func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, erro
return nil, errors.New("acme/autocert: private key cannot sign")
}
if m.state == nil {
m.state = make(map[string]*certState)
m.state = make(map[certKey]*certState)
}
s := &certState{
key: signer,
cert: cert.Certificate,
leaf: cert.Leaf,
}
m.state[name] = s
go m.renew(name, s.key, s.leaf.NotAfter)
m.state[ck] = s
go m.renew(ck, s.key, s.leaf.NotAfter)
return cert, nil
}
// cacheGet always returns a valid certificate, or an error otherwise.
// If a cached certficate exists but is not valid, ErrCacheMiss is returned.
func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate, error) {
// If a cached certificate exists but is not valid, ErrCacheMiss is returned.
func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) {
if m.Cache == nil {
return nil, ErrCacheMiss
}
data, err := m.Cache.Get(ctx, domain)
data, err := m.Cache.Get(ctx, ck.String())
if err != nil {
return nil, err
}
@ -371,7 +447,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate
}
// verify and create TLS cert
leaf, err := validCert(domain, pubDER, privKey)
leaf, err := validCert(ck, pubDER, privKey)
if err != nil {
return nil, ErrCacheMiss
}
@ -383,7 +459,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate
return tlscert, nil
}
func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error {
func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error {
if m.Cache == nil {
return nil
}
@ -415,7 +491,7 @@ func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Cert
}
}
return m.Cache.Put(ctx, domain, buf.Bytes())
return m.Cache.Put(ctx, ck.String(), buf.Bytes())
}
func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
@ -432,9 +508,9 @@ func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
//
// If the domain is already being verified, it waits for the existing verification to complete.
// Either way, createCert blocks for the duration of the whole process.
func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) {
func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
// TODO: maybe rewrite this whole piece using sync.Once
state, err := m.certState(domain)
state, err := m.certState(ck)
if err != nil {
return nil, err
}
@ -452,44 +528,44 @@ func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certifica
defer state.Unlock()
state.locked = false
der, leaf, err := m.authorizedCert(ctx, state.key, domain)
der, leaf, err := m.authorizedCert(ctx, state.key, ck)
if err != nil {
// Remove the failed state after some time,
// making the manager call createCert again on the following TLS hello.
time.AfterFunc(createCertRetryAfter, func() {
defer testDidRemoveState(domain)
defer testDidRemoveState(ck)
m.stateMu.Lock()
defer m.stateMu.Unlock()
// Verify the state hasn't changed and it's still invalid
// before deleting.
s, ok := m.state[domain]
s, ok := m.state[ck]
if !ok {
return
}
if _, err := validCert(domain, s.cert, s.key); err == nil {
if _, err := validCert(ck, s.cert, s.key); err == nil {
return
}
delete(m.state, domain)
delete(m.state, ck)
})
return nil, err
}
state.cert = der
state.leaf = leaf
go m.renew(domain, state.key, state.leaf.NotAfter)
go m.renew(ck, state.key, state.leaf.NotAfter)
return state.tlscert()
}
// certState returns a new or existing certState.
// If a new certState is returned, state.exist is false and the state is locked.
// The returned error is non-nil only in the case where a new state could not be created.
func (m *Manager) certState(domain string) (*certState, error) {
func (m *Manager) certState(ck certKey) (*certState, error) {
m.stateMu.Lock()
defer m.stateMu.Unlock()
if m.state == nil {
m.state = make(map[string]*certState)
m.state = make(map[certKey]*certState)
}
// existing state
if state, ok := m.state[domain]; ok {
if state, ok := m.state[ck]; ok {
return state, nil
}
@ -498,7 +574,7 @@ func (m *Manager) certState(domain string) (*certState, error) {
err error
key crypto.Signer
)
if m.ForceRSA {
if ck.isRSA {
key, err = rsa.GenerateKey(rand.Reader, 2048)
} else {
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
@ -512,22 +588,22 @@ func (m *Manager) certState(domain string) (*certState, error) {
locked: true,
}
state.Lock() // will be unlocked by m.certState caller
m.state[domain] = state
m.state[ck] = state
return state, nil
}
// authorizedCert starts the domain ownership verification process and requests a new cert upon success.
// The key argument is the certificate private key.
func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) {
client, err := m.acmeClient(ctx)
if err != nil {
return nil, nil, err
}
if err := m.verify(ctx, client, domain); err != nil {
if err := m.verify(ctx, client, ck.domain); err != nil {
return nil, nil, err
}
csr, err := certRequest(key, domain)
csr, err := certRequest(key, ck.domain, m.ExtraExtensions)
if err != nil {
return nil, nil, err
}
@ -535,13 +611,25 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain
if err != nil {
return nil, nil, err
}
leaf, err = validCert(domain, der, key)
leaf, err = validCert(ck, der, key)
if err != nil {
return nil, nil, err
}
return der, leaf, nil
}
// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice.
// It ignores revocation errors.
func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) {
client, err := m.acmeClient(ctx)
if err != nil {
return
}
for _, u := range uri {
client.RevokeAuthorization(ctx, u)
}
}
// verify runs the identifier (domain) authorization flow
// using each applicable ACME challenge type.
func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
@ -554,6 +642,24 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
}
m.tokensMu.RUnlock()
// Keep track of pending authzs and revoke the ones that did not validate.
pendingAuthzs := make(map[string]bool)
defer func() {
var uri []string
for k, pending := range pendingAuthzs {
if pending {
uri = append(uri, k)
}
}
if len(uri) > 0 {
// Use "detached" background context.
// The revocations need not happen in the current verification flow.
go m.revokePendingAuthz(context.Background(), uri)
}
}()
// errs accumulates challenge failure errors, printed if all fail
errs := make(map[*acme.Challenge]error)
var nextTyp int // challengeType index of the next challenge type to try
for {
// Start domain authorization and get the challenge.
@ -570,6 +676,8 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI)
}
pendingAuthzs[authz.URI] = true
// Pick the next preferred challenge.
var chal *acme.Challenge
for chal == nil && nextTyp < len(challengeTypes) {
@ -577,21 +685,30 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
nextTyp++
}
if chal == nil {
return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes)
errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain)
for chal, err := range errs {
errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err)
}
return errors.New(errorMsg)
}
cleanup, err := m.fulfill(ctx, client, chal)
if err != nil {
errs[chal] = err
continue
}
defer cleanup()
if _, err := client.Accept(ctx, chal); err != nil {
errs[chal] = err
continue
}
// A challenge is fulfilled and accepted: wait for the CA to validate.
if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil {
return nil
if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil {
errs[chal] = err
continue
}
delete(pendingAuthzs, authz.URI)
return nil
}
}
@ -634,8 +751,8 @@ func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
return nil
}
// putCertToken stores the cert under the named key in both m.certTokens map
// and m.Cache.
// putCertToken stores the token certificate with the specified name
// in both m.certTokens map and m.Cache.
func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) {
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
@ -643,17 +760,18 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi
m.certTokens = make(map[string]*tls.Certificate)
}
m.certTokens[name] = cert
m.cachePut(ctx, name, cert)
m.cachePut(ctx, certKey{domain: name, isToken: true}, cert)
}
// deleteCertToken removes the token certificate for the specified domain name
// deleteCertToken removes the token certificate with the specified name
// from both m.certTokens map and m.Cache.
func (m *Manager) deleteCertToken(name string) {
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
delete(m.certTokens, name)
if m.Cache != nil {
m.Cache.Delete(context.Background(), name)
ck := certKey{domain: name, isToken: true}
m.Cache.Delete(context.Background(), ck.String())
}
}
@ -704,7 +822,7 @@ func (m *Manager) deleteHTTPToken(tokenPath string) {
// httpTokenCacheKey returns a key at which an http-01 token value may be stored
// in the Manager's optional Cache.
func httpTokenCacheKey(tokenPath string) string {
return "http-01-" + path.Base(tokenPath)
return path.Base(tokenPath) + "+http-01"
}
// renew starts a cert renewal timer loop, one per domain.
@ -715,18 +833,18 @@ func httpTokenCacheKey(tokenPath string) string {
//
// The key argument is a certificate private key.
// The exp argument is the cert expiration time (NotAfter).
func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) {
func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) {
m.renewalMu.Lock()
defer m.renewalMu.Unlock()
if m.renewal[domain] != nil {
if m.renewal[ck] != nil {
// another goroutine is already on it
return
}
if m.renewal == nil {
m.renewal = make(map[string]*domainRenewal)
m.renewal = make(map[certKey]*domainRenewal)
}
dr := &domainRenewal{m: m, domain: domain, key: key}
m.renewal[domain] = dr
dr := &domainRenewal{m: m, ck: ck, key: key}
m.renewal[ck] = dr
dr.start(exp)
}
@ -742,7 +860,10 @@ func (m *Manager) stopRenew() {
}
func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
const keyName = "acme_account.key"
const keyName = "acme_account+key"
// Previous versions of autocert stored the value under a different key.
const legacyKeyName = "acme_account.key"
genKey := func() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
@ -753,6 +874,9 @@ func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
}
data, err := m.Cache.Get(ctx, keyName)
if err == ErrCacheMiss {
data, err = m.Cache.Get(ctx, legacyKeyName)
}
if err == ErrCacheMiss {
key, err := genKey()
if err != nil {
@ -849,12 +973,12 @@ func (s *certState) tlscert() (*tls.Certificate, error) {
}, nil
}
// certRequest creates a certificate request for the given common name cn
// and optional SANs.
func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
// certRequest generates a CSR for the given common name cn and optional SANs.
func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) {
req := &x509.CertificateRequest{
Subject: pkix.Name{CommonName: cn},
DNSNames: san,
Subject: pkix.Name{CommonName: cn},
DNSNames: san,
ExtraExtensions: ext,
}
return x509.CreateCertificateRequest(rand.Reader, req, key)
}
@ -885,12 +1009,12 @@ func parsePrivateKey(der []byte) (crypto.Signer, error) {
return nil, errors.New("acme/autocert: failed to parse private key")
}
// validCert parses a cert chain provided as der argument and verifies the leaf, der[0],
// corresponds to the private key, as well as the domain match and expiration dates.
// It doesn't do any revocation checking.
// validCert parses a cert chain provided as der argument and verifies the leaf and der[0]
// correspond to the private key, the domain and key type match, and expiration dates
// are valid. It doesn't do any revocation checking.
//
// The returned value is the verified leaf cert.
func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
func validCert(ck certKey, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
// parse public part(s)
var n int
for _, b := range der {
@ -902,7 +1026,7 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
n += copy(pub[n:], b)
}
x509Cert, err := x509.ParseCertificates(pub)
if len(x509Cert) == 0 {
if err != nil || len(x509Cert) == 0 {
return nil, errors.New("acme/autocert: no public key found")
}
// verify the leaf is not expired and matches the domain name
@ -914,10 +1038,10 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
if now.After(leaf.NotAfter) {
return nil, errors.New("acme/autocert: expired certificate")
}
if err := leaf.VerifyHostname(domain); err != nil {
if err := leaf.VerifyHostname(ck.domain); err != nil {
return nil, err
}
// ensure the leaf corresponds to the private key
// ensure the leaf corresponds to the private key and matches the certKey type
switch pub := leaf.PublicKey.(type) {
case *rsa.PublicKey:
prv, ok := key.(*rsa.PrivateKey)
@ -927,6 +1051,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
if pub.N.Cmp(prv.N) != 0 {
return nil, errors.New("acme/autocert: private key does not match public key")
}
if !ck.isRSA && !ck.isToken {
return nil, errors.New("acme/autocert: key type does not match expected value")
}
case *ecdsa.PublicKey:
prv, ok := key.(*ecdsa.PrivateKey)
if !ok {
@ -935,6 +1062,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
return nil, errors.New("acme/autocert: private key does not match public key")
}
if ck.isRSA && !ck.isToken {
return nil, errors.New("acme/autocert: key type does not match expected value")
}
default:
return nil, errors.New("acme/autocert: unknown public key algorithm")
}
@ -958,5 +1088,5 @@ var (
timeNow = time.Now
// Called when a state is removed.
testDidRemoveState = func(domain string) {}
testDidRemoveState = func(certKey) {}
)

View file

@ -5,6 +5,7 @@
package autocert
import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
@ -14,6 +15,7 @@ import (
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/base64"
"encoding/json"
"fmt"
@ -31,6 +33,12 @@ import (
"golang.org/x/crypto/acme"
)
var (
exampleDomain = "example.org"
exampleCertKey = certKey{domain: exampleDomain}
exampleCertKeyRSA = certKey{domain: exampleDomain, isRSA: true}
)
var discoTmpl = template.Must(template.New("disco").Parse(`{
"new-reg": "{{.}}/new-reg",
"new-authz": "{{.}}/new-authz",
@ -64,6 +72,7 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{
}`))
type memCache struct {
t *testing.T
mu sync.Mutex
keyData map[string][]byte
}
@ -79,7 +88,26 @@ func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) {
return v, nil
}
// filenameSafe returns whether all characters in s are printable ASCII
// and safe to use in a filename on most filesystems.
func filenameSafe(s string) bool {
for _, c := range s {
if c < 0x20 || c > 0x7E {
return false
}
switch c {
case '\\', '/', ':', '*', '?', '"', '<', '>', '|':
return false
}
}
return true
}
func (m *memCache) Put(ctx context.Context, key string, data []byte) error {
if !filenameSafe(key) {
m.t.Errorf("invalid characters in cache key %q", key)
}
m.mu.Lock()
defer m.mu.Unlock()
@ -95,12 +123,29 @@ func (m *memCache) Delete(ctx context.Context, key string) error {
return nil
}
func newMemCache() *memCache {
func newMemCache(t *testing.T) *memCache {
return &memCache{
t: t,
keyData: make(map[string][]byte),
}
}
func (m *memCache) numCerts() int {
m.mu.Lock()
defer m.mu.Unlock()
res := 0
for key := range m.keyData {
if strings.HasSuffix(key, "+token") ||
strings.HasSuffix(key, "+key") ||
strings.HasSuffix(key, "+http-01") {
continue
}
res++
}
return res
}
func dummyCert(pub interface{}, san ...string) ([]byte, error) {
return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
}
@ -137,53 +182,58 @@ func decodePayload(v interface{}, r io.Reader) error {
return json.Unmarshal(payload, v)
}
func clientHelloInfo(sni string, ecdsaSupport bool) *tls.ClientHelloInfo {
hello := &tls.ClientHelloInfo{
ServerName: sni,
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
}
if ecdsaSupport {
hello.CipherSuites = append(hello.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
}
return hello
}
func TestGetCertificate(t *testing.T) {
man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew()
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
hello := clientHelloInfo("example.org", true)
testGetCertificate(t, man, "example.org", hello)
}
func TestGetCertificate_trailingDot(t *testing.T) {
man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew()
hello := &tls.ClientHelloInfo{ServerName: "example.org."}
hello := clientHelloInfo("example.org.", true)
testGetCertificate(t, man, "example.org", hello)
}
func TestGetCertificate_ForceRSA(t *testing.T) {
man := &Manager{
Prompt: AcceptTOS,
Cache: newMemCache(),
Cache: newMemCache(t),
ForceRSA: true,
}
defer man.stopRenew()
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
testGetCertificate(t, man, "example.org", hello)
hello := clientHelloInfo(exampleDomain, true)
testGetCertificate(t, man, exampleDomain, hello)
cert, err := man.cacheGet(context.Background(), "example.org")
// ForceRSA was deprecated and is now ignored.
cert, err := man.cacheGet(context.Background(), exampleCertKey)
if err != nil {
t.Fatalf("man.cacheGet: %v", err)
}
if _, ok := cert.PrivateKey.(*rsa.PrivateKey); !ok {
t.Errorf("cert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey)
if _, ok := cert.PrivateKey.(*ecdsa.PrivateKey); !ok {
t.Errorf("cert.PrivateKey is %T; want *ecdsa.PrivateKey", cert.PrivateKey)
}
}
func TestGetCertificate_nilPrompt(t *testing.T) {
man := &Manager{}
defer man.stopRenew()
url, finish := startACMEServerStub(t, man, "example.org")
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
defer finish()
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
man.Client = &acme.Client{
Key: key,
DirectoryURL: url,
}
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
man.Client = &acme.Client{DirectoryURL: url}
hello := clientHelloInfo("example.org", true)
if _, err := man.GetCertificate(hello); err == nil {
t.Error("got certificate for example.org; wanted error")
}
@ -197,7 +247,7 @@ func TestGetCertificate_expiredCache(t *testing.T) {
}
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "example.org"},
Subject: pkix.Name{CommonName: exampleDomain},
NotAfter: time.Now(),
}
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
@ -209,16 +259,16 @@ func TestGetCertificate_expiredCache(t *testing.T) {
PrivateKey: pk,
}
man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()}
man := &Manager{Prompt: AcceptTOS, Cache: newMemCache(t)}
defer man.stopRenew()
if err := man.cachePut(context.Background(), "example.org", tlscert); err != nil {
if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil {
t.Fatalf("man.cachePut: %v", err)
}
// The expired cached cert should trigger a new cert issuance
// and return without an error.
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
testGetCertificate(t, man, "example.org", hello)
hello := clientHelloInfo(exampleDomain, true)
testGetCertificate(t, man, exampleDomain, hello)
}
func TestGetCertificate_failedAttempt(t *testing.T) {
@ -227,7 +277,6 @@ func TestGetCertificate_failedAttempt(t *testing.T) {
}))
defer ts.Close()
const example = "example.org"
d := createCertRetryAfter
f := testDidRemoveState
defer func() {
@ -236,51 +285,167 @@ func TestGetCertificate_failedAttempt(t *testing.T) {
}()
createCertRetryAfter = 0
done := make(chan struct{})
testDidRemoveState = func(domain string) {
if domain != example {
t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example)
testDidRemoveState = func(ck certKey) {
if ck != exampleCertKey {
t.Errorf("testDidRemoveState: domain = %v; want %v", ck, exampleCertKey)
}
close(done)
}
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
man := &Manager{
Prompt: AcceptTOS,
Client: &acme.Client{
Key: key,
DirectoryURL: ts.URL,
},
}
defer man.stopRenew()
hello := &tls.ClientHelloInfo{ServerName: example}
hello := clientHelloInfo(exampleDomain, true)
if _, err := man.GetCertificate(hello); err == nil {
t.Error("GetCertificate: err is nil")
}
select {
case <-time.After(5 * time.Second):
t.Errorf("took too long to remove the %q state", example)
t.Errorf("took too long to remove the %q state", exampleCertKey)
case <-done:
man.stateMu.Lock()
defer man.stateMu.Unlock()
if v, exist := man.state[example]; exist {
t.Errorf("state exists for %q: %+v", example, v)
if v, exist := man.state[exampleCertKey]; exist {
t.Errorf("state exists for %v: %+v", exampleCertKey, v)
}
}
}
// testGetCertificate_tokenCache tests the fallback of token certificate fetches
// to cache when Manager.certTokens misses. ecdsaSupport refers to the CA when
// verifying the certificate token.
func testGetCertificate_tokenCache(t *testing.T, ecdsaSupport bool) {
man1 := &Manager{
Cache: newMemCache(t),
Prompt: AcceptTOS,
}
defer man1.stopRenew()
man2 := &Manager{
Cache: man1.Cache,
Prompt: AcceptTOS,
}
defer man2.stopRenew()
// Send the verification request to a different Manager from the one that
// initiated the authorization, when they share caches.
url, finish := startACMEServerStub(t, getCertificateFromManager(man2, ecdsaSupport), "example.org")
defer finish()
man1.Client = &acme.Client{DirectoryURL: url}
hello := clientHelloInfo("example.org", true)
if _, err := man1.GetCertificate(hello); err != nil {
t.Error(err)
}
if _, err := man2.GetCertificate(hello); err != nil {
t.Error(err)
}
}
func TestGetCertificate_tokenCache(t *testing.T) {
t.Run("ecdsaSupport=true", func(t *testing.T) {
testGetCertificate_tokenCache(t, true)
})
t.Run("ecdsaSupport=false", func(t *testing.T) {
testGetCertificate_tokenCache(t, false)
})
}
func TestGetCertificate_ecdsaVsRSA(t *testing.T) {
cache := newMemCache(t)
man := &Manager{Prompt: AcceptTOS, Cache: cache}
defer man.stopRenew()
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
defer finish()
man.Client = &acme.Client{DirectoryURL: url}
cert, err := man.GetCertificate(clientHelloInfo("example.org", true))
if err != nil {
t.Error(err)
}
if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok {
t.Error("an ECDSA client was served a non-ECDSA certificate")
}
cert, err = man.GetCertificate(clientHelloInfo("example.org", false))
if err != nil {
t.Error(err)
}
if _, ok := cert.Leaf.PublicKey.(*rsa.PublicKey); !ok {
t.Error("a RSA client was served a non-RSA certificate")
}
if _, err := man.GetCertificate(clientHelloInfo("example.org", true)); err != nil {
t.Error(err)
}
if _, err := man.GetCertificate(clientHelloInfo("example.org", false)); err != nil {
t.Error(err)
}
if numCerts := cache.numCerts(); numCerts != 2 {
t.Errorf("found %d certificates in cache; want %d", numCerts, 2)
}
}
func TestGetCertificate_wrongCacheKeyType(t *testing.T) {
cache := newMemCache(t)
man := &Manager{Prompt: AcceptTOS, Cache: cache}
defer man.stopRenew()
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), exampleDomain)
defer finish()
man.Client = &acme.Client{DirectoryURL: url}
// Make an RSA cert and cache it without suffix.
pk, err := rsa.GenerateKey(rand.Reader, 512)
if err != nil {
t.Fatal(err)
}
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: exampleDomain},
NotAfter: time.Now().Add(90 * 24 * time.Hour),
}
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
if err != nil {
t.Fatal(err)
}
rsaCert := &tls.Certificate{
Certificate: [][]byte{pub},
PrivateKey: pk,
}
if err := man.cachePut(context.Background(), exampleCertKey, rsaCert); err != nil {
t.Fatalf("man.cachePut: %v", err)
}
// The RSA cached cert should be silently ignored and replaced.
cert, err := man.GetCertificate(clientHelloInfo(exampleDomain, true))
if err != nil {
t.Error(err)
}
if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok {
t.Error("an ECDSA client was served a non-ECDSA certificate")
}
if numCerts := cache.numCerts(); numCerts != 1 {
t.Errorf("found %d certificates in cache; want %d", numCerts, 1)
}
}
func getCertificateFromManager(man *Manager, ecdsaSupport bool) func(string) error {
return func(sni string) error {
_, err := man.GetCertificate(clientHelloInfo(sni, ecdsaSupport))
return err
}
}
// startACMEServerStub runs an ACME server
// The domain argument is the expected domain name of a certificate request.
func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) {
func startACMEServerStub(t *testing.T, getCertificate func(string) error, domain string) (url string, finish func()) {
// echo token-02 | shasum -a 256
// then divide result in 2 parts separated by dot
tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
verifyTokenCert := func() {
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
_, err := man.GetCertificate(hello)
if err != nil {
if err := getCertificate(tokenCertName); err != nil {
t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
return
}
@ -362,8 +527,7 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string,
tick := time.NewTicker(100 * time.Millisecond)
defer tick.Stop()
for {
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
if _, err := man.GetCertificate(hello); err != nil {
if err := getCertificate(tokenCertName); err != nil {
return
}
select {
@ -387,21 +551,13 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string,
// tests man.GetCertificate flow using the provided hello argument.
// The domain argument is the expected domain name of a certificate request.
func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) {
url, finish := startACMEServerStub(t, man, domain)
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), domain)
defer finish()
// use EC key to run faster on 386
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
man.Client = &acme.Client{
Key: key,
DirectoryURL: url,
}
man.Client = &acme.Client{DirectoryURL: url}
// simulate tls.Config.GetCertificate
var tlscert *tls.Certificate
var err error
done := make(chan struct{})
go func() {
tlscert, err = man.GetCertificate(hello)
@ -445,7 +601,7 @@ func TestVerifyHTTP01(t *testing.T) {
if w.Code != http.StatusOK {
t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK)
}
if v := string(w.Body.Bytes()); !strings.HasPrefix(v, "token-http-01.") {
if v := w.Body.String(); !strings.HasPrefix(v, "token-http-01.") {
t.Errorf("http token value = %q; want 'token-http-01.' prefix", v)
}
}
@ -505,18 +661,18 @@ func TestVerifyHTTP01(t *testing.T) {
}))
defer ca.Close()
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
m := &Manager{
Client: &acme.Client{
Key: key,
DirectoryURL: ca.URL,
},
}
http01 = m.HTTPHandler(nil)
if err := m.verify(context.Background(), m.Client, "example.org"); err != nil {
ctx := context.Background()
client, err := m.acmeClient(ctx)
if err != nil {
t.Fatalf("m.acmeClient: %v", err)
}
if err := m.verify(ctx, client, "example.org"); err != nil {
t.Errorf("m.verify: %v", err)
}
// Only tls-sni-01, tls-sni-02 and http-01 must be accepted
@ -529,6 +685,111 @@ func TestVerifyHTTP01(t *testing.T) {
}
}
func TestRevokeFailedAuthz(t *testing.T) {
// Prefill authorization URIs expected to be revoked.
// The challenges are selected in a specific order,
// each tried within a newly created authorization.
// This means each authorization URI corresponds to a different challenge type.
revokedAuthz := map[string]bool{
"/authz/0": false, // tls-sni-02
"/authz/1": false, // tls-sni-01
"/authz/2": false, // no viable challenge, but authz is created
}
var authzCount int // num. of created authorizations
var revokeCount int // num. of revoked authorizations
done := make(chan struct{}) // closed when revokeCount is 3
// ACME CA server stub, only the needed bits.
// TODO: Merge this with startACMEServerStub, making it a configurable CA for testing.
var ca *httptest.Server
ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Replay-Nonce", "nonce")
if r.Method == "HEAD" {
// a nonce request
return
}
switch r.URL.Path {
// Discovery.
case "/":
if err := discoTmpl.Execute(w, ca.URL); err != nil {
t.Errorf("discoTmpl: %v", err)
}
// Client key registration.
case "/new-reg":
w.Write([]byte("{}"))
// New domain authorization.
case "/new-authz":
w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount))
w.WriteHeader(http.StatusCreated)
if err := authzTmpl.Execute(w, ca.URL); err != nil {
t.Errorf("authzTmpl: %v", err)
}
authzCount++
// tls-sni-02 challenge "accept" request.
case "/challenge/2":
// Refuse.
http.Error(w, "won't accept tls-sni-02 challenge", http.StatusBadRequest)
// tls-sni-01 challenge "accept" request.
case "/challenge/1":
// Accept but the authorization will be "expired".
w.Write([]byte("{}"))
// Authorization requests.
case "/authz/0", "/authz/1", "/authz/2":
// Revocation requests.
if r.Method == "POST" {
var req struct{ Status string }
if err := decodePayload(&req, r.Body); err != nil {
t.Errorf("%s: decodePayload: %v", r.URL, err)
}
switch req.Status {
case "deactivated":
revokedAuthz[r.URL.Path] = true
revokeCount++
if revokeCount >= 3 {
// Last authorization is revoked.
defer close(done)
}
default:
t.Errorf("%s: req.Status = %q; want 'deactivated'", r.URL, req.Status)
}
w.Write([]byte(`{"status": "invalid"}`))
return
}
// Authorization status requests.
// Simulate abandoned authorization, deleted by the CA.
w.WriteHeader(http.StatusNotFound)
default:
http.NotFound(w, r)
t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
}
}))
defer ca.Close()
m := &Manager{
Client: &acme.Client{DirectoryURL: ca.URL},
}
// Should fail and revoke 3 authorizations.
// The first 2 are tsl-sni-02 and tls-sni-01 challenges.
// The third time an authorization is created but no viable challenge is found.
// See revokedAuthz above for more explanation.
if _, err := m.createCert(context.Background(), exampleCertKey); err == nil {
t.Errorf("m.createCert returned nil error")
}
select {
case <-time.After(3 * time.Second):
t.Error("revocations took too long")
case <-done:
// revokeCount is at least 3.
}
for uri, ok := range revokedAuthz {
if !ok {
t.Errorf("%q authorization was not revoked", uri)
}
}
}
func TestHTTPHandlerDefaultFallback(t *testing.T) {
tt := []struct {
method, url string
@ -571,7 +832,7 @@ func TestHTTPHandlerDefaultFallback(t *testing.T) {
}
func TestAccountKeyCache(t *testing.T) {
m := Manager{Cache: newMemCache()}
m := Manager{Cache: newMemCache(t)}
ctx := context.Background()
k1, err := m.accountKey(ctx)
if err != nil {
@ -587,36 +848,57 @@ func TestAccountKeyCache(t *testing.T) {
}
func TestCache(t *testing.T) {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "example.org"},
NotAfter: time.Now().Add(time.Hour),
}
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey)
cert, err := dummyCert(ecdsaKey.Public(), exampleDomain)
if err != nil {
t.Fatal(err)
}
tlscert := &tls.Certificate{
Certificate: [][]byte{pub},
PrivateKey: privKey,
ecdsaCert := &tls.Certificate{
Certificate: [][]byte{cert},
PrivateKey: ecdsaKey,
}
man := &Manager{Cache: newMemCache()}
rsaKey, err := rsa.GenerateKey(rand.Reader, 512)
if err != nil {
t.Fatal(err)
}
cert, err = dummyCert(rsaKey.Public(), exampleDomain)
if err != nil {
t.Fatal(err)
}
rsaCert := &tls.Certificate{
Certificate: [][]byte{cert},
PrivateKey: rsaKey,
}
man := &Manager{Cache: newMemCache(t)}
defer man.stopRenew()
ctx := context.Background()
if err := man.cachePut(ctx, "example.org", tlscert); err != nil {
if err := man.cachePut(ctx, exampleCertKey, ecdsaCert); err != nil {
t.Fatalf("man.cachePut: %v", err)
}
res, err := man.cacheGet(ctx, "example.org")
if err := man.cachePut(ctx, exampleCertKeyRSA, rsaCert); err != nil {
t.Fatalf("man.cachePut: %v", err)
}
res, err := man.cacheGet(ctx, exampleCertKey)
if err != nil {
t.Fatalf("man.cacheGet: %v", err)
}
if res == nil {
t.Fatal("res is nil")
if res == nil || !bytes.Equal(res.Certificate[0], ecdsaCert.Certificate[0]) {
t.Errorf("man.cacheGet = %+v; want %+v", res, ecdsaCert)
}
res, err = man.cacheGet(ctx, exampleCertKeyRSA)
if err != nil {
t.Fatalf("man.cacheGet: %v", err)
}
if res == nil || !bytes.Equal(res.Certificate[0], rsaCert.Certificate[0]) {
t.Errorf("man.cacheGet = %+v; want %+v", res, rsaCert)
}
}
@ -680,26 +962,28 @@ func TestValidCert(t *testing.T) {
}
tt := []struct {
domain string
key crypto.Signer
cert [][]byte
ok bool
ck certKey
key crypto.Signer
cert [][]byte
ok bool
}{
{"example.org", key1, [][]byte{cert1}, true},
{"example.org", key3, [][]byte{cert3}, true},
{"example.org", key1, [][]byte{cert1, cert2, cert3}, true},
{"example.org", key1, [][]byte{cert1, {1}}, false},
{"example.org", key1, [][]byte{{1}}, false},
{"example.org", key1, [][]byte{cert2}, false},
{"example.org", key2, [][]byte{cert1}, false},
{"example.org", key1, [][]byte{cert3}, false},
{"example.org", key3, [][]byte{cert1}, false},
{"example.net", key1, [][]byte{cert1}, false},
{"example.org", key1, [][]byte{early}, false},
{"example.org", key1, [][]byte{expired}, false},
{certKey{domain: "example.org"}, key1, [][]byte{cert1}, true},
{certKey{domain: "example.org", isRSA: true}, key3, [][]byte{cert3}, true},
{certKey{domain: "example.org"}, key1, [][]byte{cert1, cert2, cert3}, true},
{certKey{domain: "example.org"}, key1, [][]byte{cert1, {1}}, false},
{certKey{domain: "example.org"}, key1, [][]byte{{1}}, false},
{certKey{domain: "example.org"}, key1, [][]byte{cert2}, false},
{certKey{domain: "example.org"}, key2, [][]byte{cert1}, false},
{certKey{domain: "example.org"}, key1, [][]byte{cert3}, false},
{certKey{domain: "example.org"}, key3, [][]byte{cert1}, false},
{certKey{domain: "example.net"}, key1, [][]byte{cert1}, false},
{certKey{domain: "example.org"}, key1, [][]byte{early}, false},
{certKey{domain: "example.org"}, key1, [][]byte{expired}, false},
{certKey{domain: "example.org", isRSA: true}, key1, [][]byte{cert1}, false},
{certKey{domain: "example.org"}, key3, [][]byte{cert3}, false},
}
for i, test := range tt {
leaf, err := validCert(test.domain, test.cert, test.key)
leaf, err := validCert(test.ck, test.cert, test.key)
if err != nil && test.ok {
t.Errorf("%d: err = %v", i, err)
}
@ -748,10 +1032,99 @@ func TestManagerGetCertificateBogusSNI(t *testing.T) {
{"fo.o", "cache.Get of fo.o"},
}
for _, tt := range tests {
_, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name})
_, err := m.GetCertificate(clientHelloInfo(tt.name, true))
got := fmt.Sprint(err)
if got != tt.wantErr {
t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr)
}
}
}
func TestCertRequest(t *testing.T) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
// An extension from RFC7633. Any will do.
ext := pkix.Extension{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1},
Value: []byte("dummy"),
}
b, err := certRequest(key, "example.org", []pkix.Extension{ext}, "san.example.org")
if err != nil {
t.Fatalf("certRequest: %v", err)
}
r, err := x509.ParseCertificateRequest(b)
if err != nil {
t.Fatalf("ParseCertificateRequest: %v", err)
}
var found bool
for _, v := range r.Extensions {
if v.Id.Equal(ext.Id) {
found = true
break
}
}
if !found {
t.Errorf("want %v in Extensions: %v", ext, r.Extensions)
}
}
func TestSupportsECDSA(t *testing.T) {
tests := []struct {
CipherSuites []uint16
SignatureSchemes []tls.SignatureScheme
SupportedCurves []tls.CurveID
ecdsaOk bool
}{
{[]uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
}, nil, nil, false},
{[]uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
}, nil, nil, true},
// SignatureSchemes limits, not extends, CipherSuites
{[]uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
}, []tls.SignatureScheme{
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
}, nil, false},
{[]uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
}, []tls.SignatureScheme{
tls.PKCS1WithSHA256,
}, nil, false},
{[]uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
}, []tls.SignatureScheme{
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
}, nil, true},
{[]uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
}, []tls.SignatureScheme{
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
}, []tls.CurveID{
tls.CurveP521,
}, false},
{[]uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
}, []tls.SignatureScheme{
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
}, []tls.CurveID{
tls.CurveP256,
tls.CurveP521,
}, true},
}
for i, tt := range tests {
result := supportsECDSA(&tls.ClientHelloInfo{
CipherSuites: tt.CipherSuites,
SignatureSchemes: tt.SignatureSchemes,
SupportedCurves: tt.SupportedCurves,
})
if result != tt.ecdsaOk {
t.Errorf("%d: supportsECDSA = %v; want %v", i, result, tt.ecdsaOk)
}
}
}

View file

@ -16,10 +16,10 @@ import (
var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
// Cache is used by Manager to store and retrieve previously obtained certificates
// as opaque data.
// and other account data as opaque blobs.
//
// The key argument of the methods refers to a domain name but need not be an FQDN.
// Cache implementations should not rely on the key naming pattern.
// Cache implementations should not rely on the key naming pattern. Keys can
// include any printable ASCII characters, except the following: \/:*?"<>|
type Cache interface {
// Get returns a certificate data for the specified key.
// If there's no such key, Get returns ErrCacheMiss.

View file

@ -17,9 +17,9 @@ const renewJitter = time.Hour
// domainRenewal tracks the state used by the periodic timers
// renewing a single domain's cert.
type domainRenewal struct {
m *Manager
domain string
key crypto.Signer
m *Manager
ck certKey
key crypto.Signer
timerMu sync.Mutex
timer *time.Timer
@ -77,7 +77,7 @@ func (dr *domainRenewal) updateState(state *certState) {
dr.m.stateMu.Lock()
defer dr.m.stateMu.Unlock()
dr.key = state.key
dr.m.state[dr.domain] = state
dr.m.state[dr.ck] = state
}
// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
@ -91,7 +91,7 @@ func (dr *domainRenewal) updateState(state *certState) {
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
// a race is likely unavoidable in a distributed environment
// but we try nonetheless
if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil {
if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil {
next := dr.next(tlscert.Leaf.NotAfter)
if next > dr.m.renewBefore()+renewJitter {
signer, ok := tlscert.PrivateKey.(crypto.Signer)
@ -107,7 +107,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
}
}
der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain)
der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck)
if err != nil {
return 0, err
}
@ -120,7 +120,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
if err != nil {
return 0, err
}
if err := dr.m.cachePut(ctx, dr.domain, tlscert); err != nil {
if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil {
return 0, err
}
dr.updateState(state)

View file

@ -48,8 +48,6 @@ func TestRenewalNext(t *testing.T) {
}
func TestRenewFromCache(t *testing.T) {
const domain = "example.org"
// ACME CA server stub
var ca *httptest.Server
ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -84,7 +82,7 @@ func TestRenewFromCache(t *testing.T) {
if err != nil {
t.Fatalf("new-cert: CSR: %v", err)
}
der, err := dummyCert(csr.PublicKey, domain)
der, err := dummyCert(csr.PublicKey, exampleDomain)
if err != nil {
t.Fatalf("new-cert: dummyCert: %v", err)
}
@ -105,30 +103,28 @@ func TestRenewFromCache(t *testing.T) {
}))
defer ca.Close()
// use EC key to run faster on 386
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
man := &Manager{
Prompt: AcceptTOS,
Cache: newMemCache(),
Cache: newMemCache(t),
RenewBefore: 24 * time.Hour,
Client: &acme.Client{
Key: key,
DirectoryURL: ca.URL,
},
}
defer man.stopRenew()
// cache an almost expired cert
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
now := time.Now()
cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain)
cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
if err != nil {
t.Fatal(err)
}
tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
if err := man.cachePut(context.Background(), domain, tlscert); err != nil {
if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil {
t.Fatal(err)
}
@ -152,7 +148,7 @@ func TestRenewFromCache(t *testing.T) {
// ensure the new cert is cached
after := time.Now().Add(future)
tlscert, err := man.cacheGet(context.Background(), domain)
tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
if err != nil {
t.Fatalf("man.cacheGet: %v", err)
}
@ -163,9 +159,9 @@ func TestRenewFromCache(t *testing.T) {
// verify the old cert is also replaced in memory
man.stateMu.Lock()
defer man.stateMu.Unlock()
s := man.state[domain]
s := man.state[exampleCertKey]
if s == nil {
t.Fatalf("m.state[%q] is nil", domain)
t.Fatalf("m.state[%q] is nil", exampleCertKey)
}
tlscert, err = s.tlscert()
if err != nil {
@ -177,7 +173,7 @@ func TestRenewFromCache(t *testing.T) {
}
// trigger renew
hello := &tls.ClientHelloInfo{ServerName: domain}
hello := clientHelloInfo(exampleDomain, true)
if _, err := man.GetCertificate(hello); err != nil {
t.Fatal(err)
}
@ -191,19 +187,11 @@ func TestRenewFromCache(t *testing.T) {
}
func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
const domain = "example.org"
// use EC key to run faster on 386
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
man := &Manager{
Prompt: AcceptTOS,
Cache: newMemCache(),
Cache: newMemCache(t),
RenewBefore: 24 * time.Hour,
Client: &acme.Client{
Key: key,
DirectoryURL: "invalid",
},
}
@ -215,38 +203,42 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
t.Fatal(err)
}
now := time.Now()
newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), domain)
newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), exampleDomain)
if err != nil {
t.Fatal(err)
}
newLeaf, err := validCert(domain, [][]byte{newCert}, newKey)
newLeaf, err := validCert(exampleCertKey, [][]byte{newCert}, newKey)
if err != nil {
t.Fatal(err)
}
newTLSCert := &tls.Certificate{PrivateKey: newKey, Certificate: [][]byte{newCert}, Leaf: newLeaf}
if err := man.cachePut(context.Background(), domain, newTLSCert); err != nil {
if err := man.cachePut(context.Background(), exampleCertKey, newTLSCert); err != nil {
t.Fatal(err)
}
// set internal state to an almost expired cert
oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain)
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
oldLeaf, err := validCert(domain, [][]byte{oldCert}, key)
oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
if err != nil {
t.Fatal(err)
}
oldLeaf, err := validCert(exampleCertKey, [][]byte{oldCert}, key)
if err != nil {
t.Fatal(err)
}
man.stateMu.Lock()
if man.state == nil {
man.state = make(map[string]*certState)
man.state = make(map[certKey]*certState)
}
s := &certState{
key: key,
cert: [][]byte{oldCert},
leaf: oldLeaf,
}
man.state[domain] = s
man.state[exampleCertKey] = s
man.stateMu.Unlock()
// veriy the renewal accepted the newer cached cert
@ -267,7 +259,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
}
// ensure the cached cert was not modified
tlscert, err := man.cacheGet(context.Background(), domain)
tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
if err != nil {
t.Fatalf("man.cacheGet: %v", err)
}
@ -278,9 +270,9 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
// verify the old cert is also replaced in memory
man.stateMu.Lock()
defer man.stateMu.Unlock()
s := man.state[domain]
s := man.state[exampleCertKey]
if s == nil {
t.Fatalf("m.state[%q] is nil", domain)
t.Fatalf("m.state[%q] is nil", exampleCertKey)
}
stateKey := s.key.Public().(*ecdsa.PublicKey)
if stateKey.X.Cmp(newKey.X) != 0 || stateKey.Y.Cmp(newKey.Y) != 0 {
@ -295,9 +287,9 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
}
// verify the private key is replaced in the renewal state
r := man.renewal[domain]
r := man.renewal[exampleCertKey]
if r == nil {
t.Fatalf("m.renewal[%q] is nil", domain)
t.Fatalf("m.renewal[%q] is nil", exampleCertKey)
}
renewalKey := r.key.Public().(*ecdsa.PublicKey)
if renewalKey.X.Cmp(newKey.X) != 0 || renewalKey.Y.Cmp(newKey.Y) != 0 {
@ -307,7 +299,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
}
// assert the expiring cert is returned from state
hello := &tls.ClientHelloInfo{ServerName: domain}
hello := clientHelloInfo(exampleDomain, true)
tlscert, err := man.GetCertificate(hello)
if err != nil {
t.Fatal(err)
@ -317,7 +309,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
}
// trigger renew
go man.renew(domain, s.key, s.leaf.NotAfter)
go man.renew(exampleCertKey, s.key, s.leaf.NotAfter)
// wait for renew loop
select {
@ -325,7 +317,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
t.Fatal("renew took too long to occur")
case <-done:
// assert the new cert is returned from state after renew
hello := &tls.ClientHelloInfo{ServerName: domain}
hello := clientHelloInfo(exampleDomain, true)
tlscert, err := man.GetCertificate(hello)
if err != nil {
t.Fatal(err)

276
vendor/golang.org/x/crypto/acme/http.go generated vendored Normal file
View file

@ -0,0 +1,276 @@
// Copyright 2018 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 acme
import (
"bytes"
"context"
"crypto"
"crypto/rand"
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"strconv"
"strings"
"time"
)
// retryTimer encapsulates common logic for retrying unsuccessful requests.
// It is not safe for concurrent use.
type retryTimer struct {
// backoffFn provides backoff delay sequence for retries.
// See Client.RetryBackoff doc comment.
backoffFn func(n int, r *http.Request, res *http.Response) time.Duration
// n is the current retry attempt.
n int
}
func (t *retryTimer) inc() {
t.n++
}
// backoff pauses the current goroutine as described in Client.RetryBackoff.
func (t *retryTimer) backoff(ctx context.Context, r *http.Request, res *http.Response) error {
d := t.backoffFn(t.n, r, res)
if d <= 0 {
return fmt.Errorf("acme: no more retries for %s; tried %d time(s)", r.URL, t.n)
}
wakeup := time.NewTimer(d)
defer wakeup.Stop()
select {
case <-ctx.Done():
return ctx.Err()
case <-wakeup.C:
return nil
}
}
func (c *Client) retryTimer() *retryTimer {
f := c.RetryBackoff
if f == nil {
f = defaultBackoff
}
return &retryTimer{backoffFn: f}
}
// defaultBackoff provides default Client.RetryBackoff implementation
// using a truncated exponential backoff algorithm,
// as described in Client.RetryBackoff.
//
// The n argument is always bounded between 1 and 30.
// The returned value is always greater than 0.
func defaultBackoff(n int, r *http.Request, res *http.Response) time.Duration {
const max = 10 * time.Second
var jitter time.Duration
if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
// Set the minimum to 1ms to avoid a case where
// an invalid Retry-After value is parsed into 0 below,
// resulting in the 0 returned value which would unintentionally
// stop the retries.
jitter = (1 + time.Duration(x.Int64())) * time.Millisecond
}
if v, ok := res.Header["Retry-After"]; ok {
return retryAfter(v[0]) + jitter
}
if n < 1 {
n = 1
}
if n > 30 {
n = 30
}
d := time.Duration(1<<uint(n-1))*time.Second + jitter
if d > max {
return max
}
return d
}
// retryAfter parses a Retry-After HTTP header value,
// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
// It returns zero value if v cannot be parsed.
func retryAfter(v string) time.Duration {
if i, err := strconv.Atoi(v); err == nil {
return time.Duration(i) * time.Second
}
t, err := http.ParseTime(v)
if err != nil {
return 0
}
return t.Sub(timeNow())
}
// resOkay is a function that reports whether the provided response is okay.
// It is expected to keep the response body unread.
type resOkay func(*http.Response) bool
// wantStatus returns a function which reports whether the code
// matches the status code of a response.
func wantStatus(codes ...int) resOkay {
return func(res *http.Response) bool {
for _, code := range codes {
if code == res.StatusCode {
return true
}
}
return false
}
}
// get issues an unsigned GET request to the specified URL.
// It returns a non-error value only when ok reports true.
//
// get retries unsuccessful attempts according to c.RetryBackoff
// until the context is done or a non-retriable error is received.
func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) {
retry := c.retryTimer()
for {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
res, err := c.doNoRetry(ctx, req)
switch {
case err != nil:
return nil, err
case ok(res):
return res, nil
case isRetriable(res.StatusCode):
res.Body.Close()
retry.inc()
if err := retry.backoff(ctx, req, res); err != nil {
return nil, err
}
default:
defer res.Body.Close()
return nil, responseError(res)
}
}
}
// post issues a signed POST request in JWS format using the provided key
// to the specified URL.
// It returns a non-error value only when ok reports true.
//
// post retries unsuccessful attempts according to c.RetryBackoff
// until the context is done or a non-retriable error is received.
// It uses postNoRetry to make individual requests.
func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) {
retry := c.retryTimer()
for {
res, req, err := c.postNoRetry(ctx, key, url, body)
if err != nil {
return nil, err
}
if ok(res) {
return res, nil
}
err = responseError(res)
res.Body.Close()
switch {
// Check for bad nonce before isRetriable because it may have been returned
// with an unretriable response code such as 400 Bad Request.
case isBadNonce(err):
// Consider any previously stored nonce values to be invalid.
c.clearNonces()
case !isRetriable(res.StatusCode):
return nil, err
}
retry.inc()
if err := retry.backoff(ctx, req, res); err != nil {
return nil, err
}
}
}
// postNoRetry signs the body with the given key and POSTs it to the provided url.
// The body argument must be JSON-serializable.
// It is used by c.post to retry unsuccessful attempts.
func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) {
nonce, err := c.popNonce(ctx, url)
if err != nil {
return nil, nil, err
}
b, err := jwsEncodeJSON(body, key, nonce)
if err != nil {
return nil, nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
if err != nil {
return nil, nil, err
}
req.Header.Set("Content-Type", "application/jose+json")
res, err := c.doNoRetry(ctx, req)
if err != nil {
return nil, nil, err
}
c.addNonce(res.Header)
return res, req, nil
}
// doNoRetry issues a request req, replacing its context (if any) with ctx.
func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) {
res, err := c.httpClient().Do(req.WithContext(ctx))
if err != nil {
select {
case <-ctx.Done():
// Prefer the unadorned context error.
// (The acme package had tests assuming this, previously from ctxhttp's
// behavior, predating net/http supporting contexts natively)
// TODO(bradfitz): reconsider this in the future. But for now this
// requires no test updates.
return nil, ctx.Err()
default:
return nil, err
}
}
return res, nil
}
func (c *Client) httpClient() *http.Client {
if c.HTTPClient != nil {
return c.HTTPClient
}
return http.DefaultClient
}
// isBadNonce reports whether err is an ACME "badnonce" error.
func isBadNonce(err error) bool {
// According to the spec badNonce is urn:ietf:params:acme:error:badNonce.
// However, ACME servers in the wild return their versions of the error.
// See https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
// and https://github.com/letsencrypt/boulder/blob/0e07eacb/docs/acme-divergences.md#section-66.
ae, ok := err.(*Error)
return ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce")
}
// isRetriable reports whether a request can be retried
// based on the response status code.
//
// Note that a "bad nonce" error is returned with a non-retriable 400 Bad Request code.
// Callers should parse the response and check with isBadNonce.
func isRetriable(code int) bool {
return code <= 399 || code >= 500 || code == http.StatusTooManyRequests
}
// responseError creates an error of Error type from resp.
func responseError(resp *http.Response) error {
// don't care if ReadAll returns an error:
// json.Unmarshal will fail in that case anyway
b, _ := ioutil.ReadAll(resp.Body)
e := &wireError{Status: resp.StatusCode}
if err := json.Unmarshal(b, e); err != nil {
// this is not a regular error response:
// populate detail with anything we received,
// e.Status will already contain HTTP response code value
e.Detail = string(b)
if e.Detail == "" {
e.Detail = resp.Status
}
}
return e.error(resp.Header)
}

158
vendor/golang.org/x/crypto/acme/http_test.go generated vendored Normal file
View file

@ -0,0 +1,158 @@
// Copyright 2018 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 acme
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
"time"
)
func TestDefaultBackoff(t *testing.T) {
tt := []struct {
nretry int
retryAfter string // Retry-After header
out time.Duration // expected min; max = min + jitter
}{
{-1, "", time.Second}, // verify the lower bound is 1
{0, "", time.Second}, // verify the lower bound is 1
{100, "", 10 * time.Second}, // verify the ceiling
{1, "3600", time.Hour}, // verify the header value is used
{1, "", 1 * time.Second},
{2, "", 2 * time.Second},
{3, "", 4 * time.Second},
{4, "", 8 * time.Second},
}
for i, test := range tt {
r := httptest.NewRequest("GET", "/", nil)
resp := &http.Response{Header: http.Header{}}
if test.retryAfter != "" {
resp.Header.Set("Retry-After", test.retryAfter)
}
d := defaultBackoff(test.nretry, r, resp)
max := test.out + time.Second // + max jitter
if d < test.out || max < d {
t.Errorf("%d: defaultBackoff(%v) = %v; want between %v and %v", i, test.nretry, d, test.out, max)
}
}
}
func TestErrorResponse(t *testing.T) {
s := `{
"status": 400,
"type": "urn:acme:error:xxx",
"detail": "text"
}`
res := &http.Response{
StatusCode: 400,
Status: "400 Bad Request",
Body: ioutil.NopCloser(strings.NewReader(s)),
Header: http.Header{"X-Foo": {"bar"}},
}
err := responseError(res)
v, ok := err.(*Error)
if !ok {
t.Fatalf("err = %+v (%T); want *Error type", err, err)
}
if v.StatusCode != 400 {
t.Errorf("v.StatusCode = %v; want 400", v.StatusCode)
}
if v.ProblemType != "urn:acme:error:xxx" {
t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType)
}
if v.Detail != "text" {
t.Errorf("v.Detail = %q; want text", v.Detail)
}
if !reflect.DeepEqual(v.Header, res.Header) {
t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header)
}
}
func TestPostWithRetries(t *testing.T) {
var count int
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
if r.Method == "HEAD" {
// We expect the client to do 2 head requests to fetch
// nonces, one to start and another after getting badNonce
return
}
head, err := decodeJWSHead(r)
if err != nil {
t.Errorf("decodeJWSHead: %v", err)
} else if head.Nonce == "" {
t.Error("head.Nonce is empty")
} else if head.Nonce == "nonce1" {
// return a badNonce error to force the call to retry
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`))
return
}
// Make client.Authorize happy; we're not testing its result.
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"status":"valid"}`))
}))
defer ts.Close()
client := &Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
// This call will fail with badNonce, causing a retry
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
t.Errorf("client.Authorize 1: %v", err)
}
if count != 4 {
t.Errorf("total requests count: %d; want 4", count)
}
}
func TestRetryBackoffArgs(t *testing.T) {
const resCode = http.StatusInternalServerError
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Replay-Nonce", "test-nonce")
w.WriteHeader(resCode)
}))
defer ts.Close()
// Canceled in backoff.
ctx, cancel := context.WithCancel(context.Background())
var nretry int
backoff := func(n int, r *http.Request, res *http.Response) time.Duration {
nretry++
if n != nretry {
t.Errorf("n = %d; want %d", n, nretry)
}
if nretry == 3 {
cancel()
}
if r == nil {
t.Error("r is nil")
}
if res.StatusCode != resCode {
t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, resCode)
}
return time.Millisecond
}
client := &Client{
Key: testKey,
RetryBackoff: backoff,
dir: &Directory{AuthzURL: ts.URL},
}
if _, err := client.Authorize(ctx, "example.com"); err == nil {
t.Error("err is nil")
}
if nretry != 3 {
t.Errorf("nretry = %d; want 3", nretry)
}
}

View file

@ -104,7 +104,7 @@ func RateLimit(err error) (time.Duration, bool) {
if e.Header == nil {
return 0, true
}
return retryAfter(e.Header.Get("Retry-After"), 0), true
return retryAfter(e.Header.Get("Retry-After")), true
}
// Account is a user account. It is associated with a private key.
@ -296,8 +296,8 @@ func (e *wireError) error(h http.Header) *Error {
}
}
// CertOption is an optional argument type for the TLSSNIxChallengeCert methods for
// customizing a temporary certificate for TLS-SNI challenges.
// CertOption is an optional argument type for the TLS ChallengeCert methods for
// customizing a temporary certificate for TLS-based challenges.
type CertOption interface {
privateCertOpt()
}
@ -317,7 +317,7 @@ func (*certOptKey) privateCertOpt() {}
// WithTemplate creates an option for specifying a certificate template.
// See x509.CreateCertificate for template usage details.
//
// In TLSSNIxChallengeCert methods, the template is also used as parent,
// In TLS ChallengeCert methods, the template is also used as parent,
// resulting in a self-signed certificate.
// The DNSNames field of t is always overwritten for tls-sni challenge certs.
func WithTemplate(t *x509.Certificate) CertOption {

View file

@ -109,7 +109,6 @@ func (e *G1) Marshal() []byte {
xBytes := new(big.Int).Mod(e.p.x, p).Bytes()
yBytes := new(big.Int).Mod(e.p.y, p).Bytes()
ret := make([]byte, numBytes*2)
copy(ret[1*numBytes-len(xBytes):], xBytes)
copy(ret[2*numBytes-len(yBytes):], yBytes)
@ -224,7 +223,6 @@ func (n *G2) Marshal() []byte {
yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes()
yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes()
ret := make([]byte, numBytes*4)
copy(ret[1*numBytes-len(xxBytes):], xxBytes)
copy(ret[2*numBytes-len(xyBytes):], xyBytes)

View file

@ -9,6 +9,7 @@ package chacha20poly1305
import (
"encoding/binary"
"golang.org/x/crypto/internal/subtle"
"golang.org/x/sys/cpu"
)
@ -55,6 +56,9 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
setupState(&state, &c.key, nonce)
ret, out := sliceForAppend(dst, len(plaintext)+16)
if subtle.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap")
}
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
return ret
}
@ -69,6 +73,9 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) (
ciphertext = ciphertext[:len(ciphertext)-16]
ret, out := sliceForAppend(dst, len(ciphertext))
if subtle.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap")
}
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
for i := range out {
out[i] = 0

View file

@ -2693,22 +2693,3 @@ sealAVX2Tail512LoopB:
VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
JMP sealAVX2SealHash
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
TEXT ·cpuid(SB), NOSPLIT, $0-24
MOVL eaxArg+0(FP), AX
MOVL ecxArg+4(FP), CX
CPUID
MOVL AX, eax+8(FP)
MOVL BX, ebx+12(FP)
MOVL CX, ecx+16(FP)
MOVL DX, edx+20(FP)
RET
// func xgetbv() (eax, edx uint32)
TEXT ·xgetbv(SB),NOSPLIT,$0-8
MOVL $0, CX
XGETBV
MOVL AX, eax+0(FP)
MOVL DX, edx+4(FP)
RET

View file

@ -8,6 +8,7 @@ import (
"encoding/binary"
"golang.org/x/crypto/internal/chacha20"
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/poly1305"
)
@ -17,6 +18,9 @@ func roundTo16(n int) int {
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
if subtle.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap")
}
var polyKey [32]byte
s := chacha20.New(c.key, [3]uint32{
@ -62,6 +66,9 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
ret, out := sliceForAppend(dst, len(ciphertext))
if subtle.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap")
}
if !poly1305.Verify(&tag, polyInput, &polyKey) {
for i := range out {
out[i] = 0

View file

@ -7,6 +7,13 @@ package chacha20poly1305
var chacha20Poly1305Tests = []struct {
plaintext, aad, key, nonce, out string
}{
{
"",
"",
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
"070000004041424344454647",
"a0784d7a4716f3feb4f64e7f4b39bf04",
},
{
"4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
"50515253c0c1c2c3c4c5c6c7",

View file

@ -6,7 +6,10 @@
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032.
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
package ed25519
// This code is a port of the public domain, “ref10” implementation of ed25519
@ -31,6 +34,8 @@ const (
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
return PublicKey(publicKey)
}
// Seed returns the private key seed corresponding to priv. It is provided for
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
// in this package.
func (priv PrivateKey) Seed() []byte {
seed := make([]byte, SeedSize)
copy(seed, priv[:32])
return seed
}
// Sign signs the given message with priv.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
if rand == nil {
rand = cryptorand.Reader
}
privateKey = make([]byte, PrivateKeySize)
publicKey = make([]byte, PublicKeySize)
_, err = io.ReadFull(rand, privateKey[:32])
if err != nil {
seed := make([]byte, SeedSize)
if _, err := io.ReadFull(rand, seed); err != nil {
return nil, nil, err
}
digest := sha512.Sum512(privateKey[:32])
privateKey := NewKeyFromSeed(seed)
publicKey := make([]byte, PublicKeySize)
copy(publicKey, privateKey[32:])
return publicKey, privateKey, nil
}
// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
if l := len(seed); l != SeedSize {
panic("ed25519: bad seed length: " + strconv.Itoa(l))
}
digest := sha512.Sum512(seed)
digest[0] &= 248
digest[31] &= 127
digest[31] |= 64
@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
privateKey := make([]byte, PrivateKeySize)
copy(privateKey, seed)
copy(privateKey[32:], publicKeyBytes[:])
copy(publicKey, publicKeyBytes[:])
return publicKey, privateKey, nil
return privateKey
}
// Sign signs the message with privateKey and returns a signature. It will

View file

@ -139,6 +139,19 @@ func TestGolden(t *testing.T) {
if !Verify(pubKey, msg, sig2) {
t.Errorf("signature failed to verify on line %d", lineNo)
}
priv2 := NewKeyFromSeed(priv[:32])
if !bytes.Equal(priv[:], priv2) {
t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
}
if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
}
if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
}
}
if err := scanner.Err(); err != nil {

View file

@ -9,6 +9,8 @@ package chacha20
import (
"crypto/cipher"
"encoding/binary"
"golang.org/x/crypto/internal/subtle"
)
// assert that *Cipher implements cipher.Stream
@ -41,6 +43,13 @@ func New(key [8]uint32, nonce [3]uint32) *Cipher {
// the src buffers was passed in a single run. That is, Cipher
// maintains state and does not reset at each XORKeyStream call.
func (s *Cipher) XORKeyStream(dst, src []byte) {
if len(dst) < len(src) {
panic("chacha20: output smaller than input")
}
if subtle.InexactOverlap(dst[:len(src)], src) {
panic("chacha20: invalid buffer overlap")
}
// xor src with buffered keystream first
if s.len != 0 {
buf := s.buf[len(s.buf)-s.len:]

30
vendor/golang.org/x/crypto/internal/subtle/aliasing.go generated vendored Normal file
View file

@ -0,0 +1,30 @@
// Copyright 2018 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 subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle // import "golang.org/x/crypto/internal/subtle"
import "unsafe"
// AnyOverlap reports whether x and y share memory at any (not necessarily
// corresponding) index. The memory beyond the slice length is ignored.
func AnyOverlap(x, y []byte) bool {
return len(x) > 0 && len(y) > 0 &&
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
}
// InexactOverlap reports whether x and y share memory at any non-corresponding
// index. The memory beyond the slice length is ignored. Note that x and y can
// have different lengths and still not have any inexact overlap.
//
// InexactOverlap can be used to implement the requirements of the crypto/cipher
// AEAD, Block, BlockMode and Stream interfaces.
func InexactOverlap(x, y []byte) bool {
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
return false
}
return AnyOverlap(x, y)
}

View file

@ -0,0 +1,48 @@
// Copyright 2018 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 subtle_test
import (
"testing"
"golang.org/x/crypto/internal/subtle"
)
var a, b [100]byte
var aliasingTests = []struct {
x, y []byte
anyOverlap, inexactOverlap bool
}{
{a[:], b[:], false, false},
{a[:], b[:0], false, false},
{a[:], b[:50], false, false},
{a[40:50], a[50:60], false, false},
{a[40:50], a[60:70], false, false},
{a[:51], a[50:], true, true},
{a[:], a[:], true, false},
{a[:50], a[:60], true, false},
{a[:], nil, false, false},
{nil, nil, false, false},
{a[:], a[:0], false, false},
}
func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) {
any := subtle.AnyOverlap(x, y)
if any != anyOverlap {
t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any)
}
inexact := subtle.InexactOverlap(x, y)
if inexact != inexactOverlap {
t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any)
}
}
func TestAliasing(t *testing.T) {
for i, tt := range aliasingTests {
testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap)
testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap)
}
}

View file

@ -35,6 +35,7 @@ This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
package secretbox // import "golang.org/x/crypto/nacl/secretbox"
import (
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/poly1305"
"golang.org/x/crypto/salsa20/salsa"
)
@ -87,6 +88,9 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
copy(poly1305Key[:], firstBlock[:])
ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
if subtle.AnyOverlap(out, message) {
panic("nacl: invalid buffer overlap")
}
// We XOR up to 32 bytes of message with the keystream generated from
// the first block.
@ -118,7 +122,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
// Open authenticates and decrypts a box produced by Seal and appends the
// message to out, which must not overlap box. The output will be Overhead
// bytes smaller than box.
func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
if len(box) < Overhead {
return nil, false
}
@ -143,6 +147,9 @@ func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool)
}
ret, out := sliceForAppend(out, len(box)-Overhead)
if subtle.AnyOverlap(out, box) {
panic("nacl: invalid buffer overlap")
}
// We XOR up to 32 bytes of box with the keystream generated from
// the first block.

View file

@ -24,6 +24,7 @@ import (
"io"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/internal/subtle"
)
// Overhead is the number of bytes of overhead when signing a message.
@ -47,6 +48,9 @@ func GenerateKey(rand io.Reader) (publicKey *[32]byte, privateKey *[64]byte, err
func Sign(out, message []byte, privateKey *[64]byte) []byte {
sig := ed25519.Sign(ed25519.PrivateKey((*privateKey)[:]), message)
ret, out := sliceForAppend(out, Overhead+len(message))
if subtle.AnyOverlap(out, message) {
panic("nacl: invalid buffer overlap")
}
copy(out, sig)
copy(out[Overhead:], message)
return ret
@ -63,6 +67,9 @@ func Open(out, signedMessage []byte, publicKey *[32]byte) ([]byte, bool) {
return nil, false
}
ret, out := sliceForAppend(out, len(signedMessage)-Overhead)
if subtle.AnyOverlap(out, signedMessage) {
panic("nacl: invalid buffer overlap")
}
copy(out, signedMessage[Overhead:])
return ret, true
}

View file

@ -346,22 +346,25 @@ EachPacket:
switch pkt := p.(type) {
case *packet.UserId:
// Make a new Identity object, that we might wind up throwing away.
// We'll only add it if we get a valid self-signature over this
// userID.
current = new(Identity)
current.Name = pkt.Id
current.UserId = pkt
e.Identities[pkt.Id] = current
for {
p, err = packets.Next()
if err == io.EOF {
return nil, io.ErrUnexpectedEOF
break EachPacket
} else if err != nil {
return nil, err
}
sig, ok := p.(*packet.Signature)
if !ok {
return nil, errors.StructuralError("user ID packet not followed by self-signature")
packets.Unread(p)
continue EachPacket
}
if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
@ -369,9 +372,10 @@ EachPacket:
return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error())
}
current.SelfSignature = sig
break
e.Identities[pkt.Id] = current
} else {
current.Signatures = append(current.Signatures, sig)
}
current.Signatures = append(current.Signatures, sig)
}
case *packet.Signature:
if pkt.SigType == packet.SigTypeKeyRevocation {
@ -500,6 +504,10 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
IssuerKeyId: &e.PrimaryKey.KeyId,
},
}
err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config)
if err != nil {
return nil, err
}
// If the user passes in a DefaultHash via packet.Config,
// set the PreferredHash for the SelfSignature.
@ -529,13 +537,16 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
}
e.Subkeys[0].PublicKey.IsSubkey = true
e.Subkeys[0].PrivateKey.IsSubkey = true
err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config)
if err != nil {
return nil, err
}
return e, nil
}
// SerializePrivate serializes an Entity, including private key material, to
// the given Writer. For now, it must only be used on an Entity returned from
// NewEntity.
// SerializePrivate serializes an Entity, including private key material, but
// excluding signatures from other entities, to the given Writer.
// Identities and subkeys are re-signed in case they changed since NewEntry.
// If config is nil, sensible defaults will be used.
func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
err = e.PrivateKey.Serialize(w)
@ -573,8 +584,8 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error
return nil
}
// Serialize writes the public part of the given Entity to w. (No private
// key material will be output).
// Serialize writes the public part of the given Entity to w, including
// signatures from other entities. No private key material will be output.
func (e *Entity) Serialize(w io.Writer) error {
err := e.PrimaryKey.Serialize(w)
if err != nil {

View file

@ -29,16 +29,16 @@ func TestKeyExpiry(t *testing.T) {
//
// So this should select the newest, non-expired encryption key.
key, _ := entity.encryptionKey(time1)
if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" {
t.Errorf("Expected key 1ABB25A0 at time %s, but got key %s", time1.Format(timeFormat), id)
if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected {
t.Errorf("Expected key %s at time %s, but got key %s", expected, time1.Format(timeFormat), id)
}
// Once the first encryption subkey has expired, the second should be
// selected.
time2, _ := time.Parse(timeFormat, "2013-07-09")
key, _ = entity.encryptionKey(time2)
if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" {
t.Errorf("Expected key 96A672F5 at time %s, but got key %s", time2.Format(timeFormat), id)
if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected {
t.Errorf("Expected key %s at time %s, but got key %s", expected, time2.Format(timeFormat), id)
}
// Once all the keys have expired, nothing should be returned.
@ -105,6 +105,33 @@ func TestGoodCrossSignature(t *testing.T) {
}
}
func TestRevokedUserID(t *testing.T) {
// This key contains 2 UIDs, one of which is revoked:
// [ultimate] (1) Golang Gopher <no-reply@golang.com>
// [ revoked] (2) Golang Gopher <revoked@golang.com>
keys, err := ReadArmoredKeyRing(bytes.NewBufferString(revokedUserIDKey))
if err != nil {
t.Fatal(err)
}
if len(keys) != 1 {
t.Fatal("Failed to read key with a revoked user id")
}
var identities []*Identity
for _, identity := range keys[0].Identities {
identities = append(identities, identity)
}
if numIdentities, numExpected := len(identities), 1; numIdentities != numExpected {
t.Errorf("obtained %d identities, expected %d", numIdentities, numExpected)
}
if identityName, expectedName := identities[0].Name, "Golang Gopher <no-reply@golang.com>"; identityName != expectedName {
t.Errorf("obtained identity %s expected %s", identityName, expectedName)
}
}
// TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission.
func TestExternallyRevocableKey(t *testing.T) {
kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex))
@ -370,6 +397,20 @@ func TestNewEntityWithoutPreferredSymmetric(t *testing.T) {
}
}
func TestNewEntityPublicSerialization(t *testing.T) {
entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", nil)
if err != nil {
t.Fatal(err)
}
serializedEntity := bytes.NewBuffer(nil)
entity.Serialize(serializedEntity)
_, err = ReadEntity(packet.NewReader(bytes.NewBuffer(serializedEntity.Bytes())))
if err != nil {
t.Fatal(err)
}
}
const expiringKeyHex = "988d0451d1ec5d010400ba3385721f2dc3f4ab096b2ee867ab77213f0a27a8538441c35d2fa225b08798a1439a66a5150e6bdc3f40f5d28d588c712394c632b6299f77db8c0d48d37903fb72ebd794d61be6aa774688839e5fdecfe06b2684cc115d240c98c66cb1ef22ae84e3aa0c2b0c28665c1e7d4d044e7f270706193f5223c8d44e0d70b7b8da830011010001b40f4578706972792074657374206b657988be041301020028050251d1ec5d021b03050900278d00060b090807030206150802090a0b0416020301021e01021780000a091072589ad75e237d8c033503fd10506d72837834eb7f994117740723adc39227104b0d326a1161871c0b415d25b4aedef946ca77ea4c05af9c22b32cf98be86ab890111fced1ee3f75e87b7cc3c00dc63bbc85dfab91c0dc2ad9de2c4d13a34659333a85c6acc1a669c5e1d6cecb0cf1e56c10e72d855ae177ddc9e766f9b2dda57ccbb75f57156438bbdb4e42b88d0451d1ec5d0104009c64906559866c5cb61578f5846a94fcee142a489c9b41e67b12bb54cfe86eb9bc8566460f9a720cb00d6526fbccfd4f552071a8e3f7744b1882d01036d811ee5a3fb91a1c568055758f43ba5d2c6a9676b012f3a1a89e47bbf624f1ad571b208f3cc6224eb378f1645dd3d47584463f9eadeacfd1ce6f813064fbfdcc4b5a53001101000188a504180102000f021b0c050251d1f06b050900093e89000a091072589ad75e237d8c20e00400ab8310a41461425b37889c4da28129b5fae6084fafbc0a47dd1adc74a264c6e9c9cc125f40462ee1433072a58384daef88c961c390ed06426a81b464a53194c4e291ddd7e2e2ba3efced01537d713bd111f48437bde2363446200995e8e0d4e528dda377fd1e8f8ede9c8e2198b393bd86852ce7457a7e3daf74d510461a5b77b88d0451d1ece8010400b3a519f83ab0010307e83bca895170acce8964a044190a2b368892f7a244758d9fc193482648acb1fb9780d28cc22d171931f38bb40279389fc9bf2110876d4f3db4fcfb13f22f7083877fe56592b3b65251312c36f83ffcb6d313c6a17f197dd471f0712aad15a8537b435a92471ba2e5b0c72a6c72536c3b567c558d7b6051001101000188a504180102000f021b0c050251d1f07b050900279091000a091072589ad75e237d8ce69e03fe286026afacf7c97ee20673864d4459a2240b5655219950643c7dba0ac384b1d4359c67805b21d98211f7b09c2a0ccf6410c8c04d4ff4a51293725d8d6570d9d8bb0e10c07d22357caeb49626df99c180be02d77d1fe8ed25e7a54481237646083a9f89a11566cd20b9e995b1487c5f9e02aeb434f3a1897cd416dd0a87861838da3e9e"
const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98"
const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f"
@ -467,3 +508,42 @@ SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/
MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70=
=vtbN
-----END PGP PUBLIC KEY BLOCK-----`
const revokedUserIDKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFsgO5EBCADhREPmcjsPkXe1z7ctvyWL0S7oa9JaoGZ9oPDHFDlQxd0qlX2e
DZJZDg0qYvVixmaULIulApq1puEsaJCn3lHUbHlb4PYKwLEywYXM28JN91KtLsz/
uaEX2KC5WqeP40utmzkNLq+oRX/xnRMgwbO7yUNVG2UlEa6eI+xOXO3YtLdmJMBW
ClQ066ZnOIzEo1JxnIwha1CDBMWLLfOLrg6l8InUqaXbtEBbnaIYO6fXVXELUjkx
nmk7t/QOk0tXCy8muH9UDqJkwDUESY2l79XwBAcx9riX8vY7vwC34pm22fAUVLCJ
x1SJx0J8bkeNp38jKM2Zd9SUQqSbfBopQ4pPABEBAAG0I0dvbGFuZyBHb3BoZXIg
PG5vLXJlcGx5QGdvbGFuZy5jb20+iQFUBBMBCgA+FiEE5Ik5JLcNx6l6rZfw1oFy
9I6cUoMFAlsgO5ECGwMFCQPCZwAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ
1oFy9I6cUoMIkwf8DNPeD23i4jRwd/pylbvxwZintZl1fSwTJW1xcOa1emXaEtX2
depuqhP04fjlRQGfsYAQh7X9jOJxAHjTmhqFBi5sD7QvKU00cPFYbJ/JTx0B41bl
aXnSbGhRPh63QtEZL7ACAs+shwvvojJqysx7kyVRu0EW2wqjXdHwR/SJO6nhNBa2
DXzSiOU/SUA42mmG+5kjF8Aabq9wPwT9wjraHShEweNerNMmOqJExBOy3yFeyDpa
XwEZFzBfOKoxFNkIaVf5GSdIUGhFECkGvBMB935khftmgR8APxdU4BE7XrXexFJU
8RCuPXonm4WQOwTWR0vQg64pb2WKAzZ8HhwTGbQiR29sYW5nIEdvcGhlciA8cmV2
b2tlZEBnb2xhbmcuY29tPokBNgQwAQoAIBYhBOSJOSS3Dcepeq2X8NaBcvSOnFKD
BQJbIDv3Ah0AAAoJENaBcvSOnFKDfWMIAKhI/Tvu3h8fSUxp/gSAcduT6bC1JttG
0lYQ5ilKB/58lBUA5CO3ZrKDKlzW3M8VEcvohVaqeTMKeoQd5rCZq8KxHn/KvN6N
s85REfXfniCKfAbnGgVXX3kDmZ1g63pkxrFu0fDZjVDXC6vy+I0sGyI/Inro0Pzb
tvn0QCsxjapKK15BtmSrpgHgzVqVg0cUp8vqZeKFxarYbYB2idtGRci4b9tObOK0
BSTVFy26+I/mrFGaPrySYiy2Kz5NMEcRhjmTxJ8jSwEr2O2sUR0yjbgUAXbTxDVE
/jg5fQZ1ACvBRQnB7LvMHcInbzjyeTM3FazkkSYQD6b97+dkWwb1iWG5AQ0EWyA7
kQEIALkg04REDZo1JgdYV4x8HJKFS4xAYWbIva1ZPqvDNmZRUbQZR2+gpJGEwn7z
VofGvnOYiGW56AS5j31SFf5kro1+1bZQ5iOONBng08OOo58/l1hRseIIVGB5TGSa
PCdChKKHreJI6hS3mShxH6hdfFtiZuB45rwoaArMMsYcjaezLwKeLc396cpUwwcZ
snLUNd1Xu5EWEF2OdFkZ2a1qYdxBvAYdQf4+1Nr+NRIx1u1NS9c8jp3PuMOkrQEi
bNtc1v6v0Jy52mKLG4y7mC/erIkvkQBYJdxPaP7LZVaPYc3/xskcyijrJ/5ufoD8
K71/ShtsZUXSQn9jlRaYR0EbojMAEQEAAYkBPAQYAQoAJhYhBOSJOSS3Dcepeq2X
8NaBcvSOnFKDBQJbIDuRAhsMBQkDwmcAAAoJENaBcvSOnFKDkFMIAIt64bVZ8x7+
TitH1bR4pgcNkaKmgKoZz6FXu80+SnbuEt2NnDyf1cLOSimSTILpwLIuv9Uft5Pb
OraQbYt3xi9yrqdKqGLv80bxqK0NuryNkvh9yyx5WoG1iKqMj9/FjGghuPrRaT4l
QinNAghGVkEy1+aXGFrG2DsOC1FFI51CC2WVTzZ5RwR2GpiNRfESsU1rZAUqf/2V
yJl9bD5R4SUNy8oQmhOxi+gbhD4Ao34e4W0ilibslI/uawvCiOwlu5NGd8zv5n+U
heiQvzkApQup5c+BhH5zFDFdKJ2CBByxw9+7QjMFI/wgLixKuE0Ob2kAokXf7RlB
7qTZOahrETw=
=IKnw
-----END PGP PUBLIC KEY BLOCK-----`

View file

@ -124,7 +124,7 @@ func checkSignedMessage(t *testing.T, signedHex, expected string) {
return
}
if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.IsSymmetricallyEncrypted {
if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.DecryptedWith != (Key{}) {
t.Errorf("bad MessageDetails: %#v", md)
}

View file

@ -5,7 +5,6 @@
package poly1305
import (
"bytes"
"encoding/hex"
"flag"
"testing"
@ -14,80 +13,51 @@ import (
var stressFlag = flag.Bool("stress", false, "run slow stress tests")
var testData = []struct {
in, k, correct []byte
}{
{
[]byte("Hello world!"),
[]byte("this is 32-byte key for Poly1305"),
[]byte{0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0},
},
{
make([]byte, 32),
[]byte("this is 32-byte key for Poly1305"),
[]byte{0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07},
},
{
make([]byte, 2007),
[]byte("this is 32-byte key for Poly1305"),
[]byte{0xda, 0x84, 0xbc, 0xab, 0x02, 0x67, 0x6c, 0x38, 0xcd, 0xb0, 0x15, 0x60, 0x42, 0x74, 0xc2, 0xaa},
},
{
make([]byte, 2007),
make([]byte, 32),
make([]byte, 16),
},
{
// This test triggers an edge-case. See https://go-review.googlesource.com/#/c/30101/.
[]byte{0x81, 0xd8, 0xb2, 0xe4, 0x6a, 0x25, 0x21, 0x3b, 0x58, 0xfe, 0xe4, 0x21, 0x3a, 0x2a, 0x28, 0xe9, 0x21, 0xc1, 0x2a, 0x96, 0x32, 0x51, 0x6d, 0x3b, 0x73, 0x27, 0x27, 0x27, 0xbe, 0xcf, 0x21, 0x29},
[]byte{0x3b, 0x3a, 0x29, 0xe9, 0x3b, 0x21, 0x3a, 0x5c, 0x5c, 0x3b, 0x3b, 0x05, 0x3a, 0x3a, 0x8c, 0x0d},
[]byte{0x6d, 0xc1, 0x8b, 0x8c, 0x34, 0x4c, 0xd7, 0x99, 0x27, 0x11, 0x8b, 0xbe, 0x84, 0xb7, 0xf3, 0x14},
},
{
// This test generates a result of (2^130-1) % (2^130-5).
[]byte{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
[]byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
{
// This test generates a result of (2^130-6) % (2^130-5).
[]byte{
0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
[]byte{0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
},
{
// This test generates a result of (2^130-5) % (2^130-5).
[]byte{
0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
},
type test struct {
in string
key string
tag string
}
func testSum(t *testing.T, unaligned bool) {
var out [16]byte
var key [32]byte
func (t *test) Input() []byte {
in, err := hex.DecodeString(t.in)
if err != nil {
panic(err)
}
return in
}
func (t *test) Key() [32]byte {
buf, err := hex.DecodeString(t.key)
if err != nil {
panic(err)
}
var key [32]byte
copy(key[:], buf[:32])
return key
}
func (t *test) Tag() [16]byte {
buf, err := hex.DecodeString(t.tag)
if err != nil {
panic(err)
}
var tag [16]byte
copy(tag[:], buf[:16])
return tag
}
func testSum(t *testing.T, unaligned bool, sumImpl func(tag *[TagSize]byte, msg []byte, key *[32]byte)) {
var tag [16]byte
for i, v := range testData {
in := v.in
in := v.Input()
if unaligned {
in = unalignBytes(in)
}
copy(key[:], v.k)
Sum(&out, in, &key)
if !bytes.Equal(out[:], v.correct) {
t.Errorf("%d: expected %x, got %x", i, v.correct, out[:])
key := v.Key()
sumImpl(&tag, in, &key)
if tag != v.Tag() {
t.Errorf("%d: expected %x, got %x", i, v.Tag(), tag[:])
}
}
}
@ -125,8 +95,10 @@ func TestBurnin(t *testing.T) {
}
}
func TestSum(t *testing.T) { testSum(t, false) }
func TestSumUnaligned(t *testing.T) { testSum(t, true) }
func TestSum(t *testing.T) { testSum(t, false, Sum) }
func TestSumUnaligned(t *testing.T) { testSum(t, true, Sum) }
func TestSumGeneric(t *testing.T) { testSum(t, false, sumGeneric) }
func TestSumGenericUnaligned(t *testing.T) { testSum(t, true, sumGeneric) }
func benchmark(b *testing.B, size int, unaligned bool) {
var out [16]byte
@ -146,6 +118,7 @@ func Benchmark64(b *testing.B) { benchmark(b, 64, false) }
func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) }
func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) }
func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) }
func Benchmark2M(b *testing.B) { benchmark(b, 2097152, true) }
func unalignBytes(in []byte) []byte {
out := make([]byte, len(in)+1)

14
vendor/golang.org/x/crypto/poly1305/sum_noasm.go generated vendored Normal file
View file

@ -0,0 +1,14 @@
// Copyright 2018 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 s390x,!go1.11 !arm,!amd64,!s390x gccgo appengine nacl
package poly1305
// Sum generates an authenticator for msg using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
sumGeneric(out, msg, key)
}

View file

@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64,!arm gccgo appengine nacl
package poly1305
import "encoding/binary"
// Sum generates an authenticator for msg using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) {
// sumGeneric generates an authenticator for msg using a one-time key and
// puts the 16-byte result into out. This is the generic implementation of
// Sum and should be called if no assembly implementation is available.
func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
var (
h0, h1, h2, h3, h4 uint32 // the hash accumulators
r0, r1, r2, r3, r4 uint64 // the r part of the key

49
vendor/golang.org/x/crypto/poly1305/sum_s390x.go generated vendored Normal file
View file

@ -0,0 +1,49 @@
// Copyright 2018 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 s390x,go1.11,!gccgo,!appengine
package poly1305
// hasVectorFacility reports whether the machine supports
// the vector facility (vx).
func hasVectorFacility() bool
// hasVMSLFacility reports whether the machine supports
// Vector Multiply Sum Logical (VMSL).
func hasVMSLFacility() bool
var hasVX = hasVectorFacility()
var hasVMSL = hasVMSLFacility()
// poly1305vx is an assembly implementation of Poly1305 that uses vector
// instructions. It must only be called if the vector facility (vx) is
// available.
//go:noescape
func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
// poly1305vmsl is an assembly implementation of Poly1305 that uses vector
// instructions, including VMSL. It must only be called if the vector facility (vx) is
// available and if VMSL is supported.
//go:noescape
func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
// Sum generates an authenticator for m using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) {
if hasVX {
var mPtr *byte
if len(m) > 0 {
mPtr = &m[0]
}
if hasVMSL && len(m) > 256 {
poly1305vmsl(out, mPtr, uint64(len(m)), key)
} else {
poly1305vx(out, mPtr, uint64(len(m)), key)
}
} else {
sumGeneric(out, m, key)
}
}

400
vendor/golang.org/x/crypto/poly1305/sum_s390x.s generated vendored Normal file
View file

@ -0,0 +1,400 @@
// Copyright 2018 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 s390x,go1.11,!gccgo,!appengine
#include "textflag.h"
// Implementation of Poly1305 using the vector facility (vx).
// constants
#define MOD26 V0
#define EX0 V1
#define EX1 V2
#define EX2 V3
// temporaries
#define T_0 V4
#define T_1 V5
#define T_2 V6
#define T_3 V7
#define T_4 V8
// key (r)
#define R_0 V9
#define R_1 V10
#define R_2 V11
#define R_3 V12
#define R_4 V13
#define R5_1 V14
#define R5_2 V15
#define R5_3 V16
#define R5_4 V17
#define RSAVE_0 R5
#define RSAVE_1 R6
#define RSAVE_2 R7
#define RSAVE_3 R8
#define RSAVE_4 R9
#define R5SAVE_1 V28
#define R5SAVE_2 V29
#define R5SAVE_3 V30
#define R5SAVE_4 V31
// message block
#define F_0 V18
#define F_1 V19
#define F_2 V20
#define F_3 V21
#define F_4 V22
// accumulator
#define H_0 V23
#define H_1 V24
#define H_2 V25
#define H_3 V26
#define H_4 V27
GLOBL ·keyMask<>(SB), RODATA, $16
DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f
DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f
GLOBL ·bswapMask<>(SB), RODATA, $16
DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908
DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100
GLOBL ·constants<>(SB), RODATA, $64
// MOD26
DATA ·constants<>+0(SB)/8, $0x3ffffff
DATA ·constants<>+8(SB)/8, $0x3ffffff
// EX0
DATA ·constants<>+16(SB)/8, $0x0006050403020100
DATA ·constants<>+24(SB)/8, $0x1016151413121110
// EX1
DATA ·constants<>+32(SB)/8, $0x060c0b0a09080706
DATA ·constants<>+40(SB)/8, $0x161c1b1a19181716
// EX2
DATA ·constants<>+48(SB)/8, $0x0d0d0d0d0d0f0e0d
DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d
// h = (f*g) % (2**130-5) [partial reduction]
#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \
VMLOF f0, g0, h0 \
VMLOF f0, g1, h1 \
VMLOF f0, g2, h2 \
VMLOF f0, g3, h3 \
VMLOF f0, g4, h4 \
VMLOF f1, g54, T_0 \
VMLOF f1, g0, T_1 \
VMLOF f1, g1, T_2 \
VMLOF f1, g2, T_3 \
VMLOF f1, g3, T_4 \
VMALOF f2, g53, h0, h0 \
VMALOF f2, g54, h1, h1 \
VMALOF f2, g0, h2, h2 \
VMALOF f2, g1, h3, h3 \
VMALOF f2, g2, h4, h4 \
VMALOF f3, g52, T_0, T_0 \
VMALOF f3, g53, T_1, T_1 \
VMALOF f3, g54, T_2, T_2 \
VMALOF f3, g0, T_3, T_3 \
VMALOF f3, g1, T_4, T_4 \
VMALOF f4, g51, h0, h0 \
VMALOF f4, g52, h1, h1 \
VMALOF f4, g53, h2, h2 \
VMALOF f4, g54, h3, h3 \
VMALOF f4, g0, h4, h4 \
VAG T_0, h0, h0 \
VAG T_1, h1, h1 \
VAG T_2, h2, h2 \
VAG T_3, h3, h3 \
VAG T_4, h4, h4
// carry h0->h1 h3->h4, h1->h2 h4->h0, h0->h1 h2->h3, h3->h4
#define REDUCE(h0, h1, h2, h3, h4) \
VESRLG $26, h0, T_0 \
VESRLG $26, h3, T_1 \
VN MOD26, h0, h0 \
VN MOD26, h3, h3 \
VAG T_0, h1, h1 \
VAG T_1, h4, h4 \
VESRLG $26, h1, T_2 \
VESRLG $26, h4, T_3 \
VN MOD26, h1, h1 \
VN MOD26, h4, h4 \
VESLG $2, T_3, T_4 \
VAG T_3, T_4, T_4 \
VAG T_2, h2, h2 \
VAG T_4, h0, h0 \
VESRLG $26, h2, T_0 \
VESRLG $26, h0, T_1 \
VN MOD26, h2, h2 \
VN MOD26, h0, h0 \
VAG T_0, h3, h3 \
VAG T_1, h1, h1 \
VESRLG $26, h3, T_2 \
VN MOD26, h3, h3 \
VAG T_2, h4, h4
// expand in0 into d[0] and in1 into d[1]
#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \
VGBM $0x0707, d1 \ // d1=tmp
VPERM in0, in1, EX2, d4 \
VPERM in0, in1, EX0, d0 \
VPERM in0, in1, EX1, d2 \
VN d1, d4, d4 \
VESRLG $26, d0, d1 \
VESRLG $30, d2, d3 \
VESRLG $4, d2, d2 \
VN MOD26, d0, d0 \
VN MOD26, d1, d1 \
VN MOD26, d2, d2 \
VN MOD26, d3, d3
// pack h4:h0 into h1:h0 (no carry)
#define PACK(h0, h1, h2, h3, h4) \
VESLG $26, h1, h1 \
VESLG $26, h3, h3 \
VO h0, h1, h0 \
VO h2, h3, h2 \
VESLG $4, h2, h2 \
VLEIB $7, $48, h1 \
VSLB h1, h2, h2 \
VO h0, h2, h0 \
VLEIB $7, $104, h1 \
VSLB h1, h4, h3 \
VO h3, h0, h0 \
VLEIB $7, $24, h1 \
VSRLB h1, h4, h1
// if h > 2**130-5 then h -= 2**130-5
#define MOD(h0, h1, t0, t1, t2) \
VZERO t0 \
VLEIG $1, $5, t0 \
VACCQ h0, t0, t1 \
VAQ h0, t0, t0 \
VONE t2 \
VLEIG $1, $-4, t2 \
VAQ t2, t1, t1 \
VACCQ h1, t1, t1 \
VONE t2 \
VAQ t2, t1, t1 \
VN h0, t1, t2 \
VNC t0, t1, t1 \
VO t1, t2, h0
// func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]key)
TEXT ·poly1305vx(SB), $0-32
// This code processes up to 2 blocks (32 bytes) per iteration
// using the algorithm described in:
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key
// load MOD26, EX0, EX1 and EX2
MOVD $·constants<>(SB), R5
VLM (R5), MOD26, EX2
// setup r
VL (R4), T_0
MOVD $·keyMask<>(SB), R6
VL (R6), T_1
VN T_0, T_1, T_0
EXPAND(T_0, T_0, R_0, R_1, R_2, R_3, R_4)
// setup r*5
VLEIG $0, $5, T_0
VLEIG $1, $5, T_0
// store r (for final block)
VMLOF T_0, R_1, R5SAVE_1
VMLOF T_0, R_2, R5SAVE_2
VMLOF T_0, R_3, R5SAVE_3
VMLOF T_0, R_4, R5SAVE_4
VLGVG $0, R_0, RSAVE_0
VLGVG $0, R_1, RSAVE_1
VLGVG $0, R_2, RSAVE_2
VLGVG $0, R_3, RSAVE_3
VLGVG $0, R_4, RSAVE_4
// skip r**2 calculation
CMPBLE R3, $16, skip
// calculate r**2
MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5SAVE_1, R5SAVE_2, R5SAVE_3, R5SAVE_4, H_0, H_1, H_2, H_3, H_4)
REDUCE(H_0, H_1, H_2, H_3, H_4)
VLEIG $0, $5, T_0
VLEIG $1, $5, T_0
VMLOF T_0, H_1, R5_1
VMLOF T_0, H_2, R5_2
VMLOF T_0, H_3, R5_3
VMLOF T_0, H_4, R5_4
VLR H_0, R_0
VLR H_1, R_1
VLR H_2, R_2
VLR H_3, R_3
VLR H_4, R_4
// initialize h
VZERO H_0
VZERO H_1
VZERO H_2
VZERO H_3
VZERO H_4
loop:
CMPBLE R3, $32, b2
VLM (R2), T_0, T_1
SUB $32, R3
MOVD $32(R2), R2
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
VLEIB $4, $1, F_4
VLEIB $12, $1, F_4
multiply:
VAG H_0, F_0, F_0
VAG H_1, F_1, F_1
VAG H_2, F_2, F_2
VAG H_3, F_3, F_3
VAG H_4, F_4, F_4
MULTIPLY(F_0, F_1, F_2, F_3, F_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4)
REDUCE(H_0, H_1, H_2, H_3, H_4)
CMPBNE R3, $0, loop
finish:
// sum vectors
VZERO T_0
VSUMQG H_0, T_0, H_0
VSUMQG H_1, T_0, H_1
VSUMQG H_2, T_0, H_2
VSUMQG H_3, T_0, H_3
VSUMQG H_4, T_0, H_4
// h may be >= 2*(2**130-5) so we need to reduce it again
REDUCE(H_0, H_1, H_2, H_3, H_4)
// carry h1->h4
VESRLG $26, H_1, T_1
VN MOD26, H_1, H_1
VAQ T_1, H_2, H_2
VESRLG $26, H_2, T_2
VN MOD26, H_2, H_2
VAQ T_2, H_3, H_3
VESRLG $26, H_3, T_3
VN MOD26, H_3, H_3
VAQ T_3, H_4, H_4
// h is now < 2*(2**130-5)
// pack h into h1 (hi) and h0 (lo)
PACK(H_0, H_1, H_2, H_3, H_4)
// if h > 2**130-5 then h -= 2**130-5
MOD(H_0, H_1, T_0, T_1, T_2)
// h += s
MOVD $·bswapMask<>(SB), R5
VL (R5), T_1
VL 16(R4), T_0
VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big)
VAQ T_0, H_0, H_0
VPERM H_0, H_0, T_1, H_0 // reverse bytes (to little)
VST H_0, (R1)
RET
b2:
CMPBLE R3, $16, b1
// 2 blocks remaining
SUB $17, R3
VL (R2), T_0
VLL R3, 16(R2), T_1
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, T_1
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
CMPBNE R3, $16, 2(PC)
VLEIB $12, $1, F_4
VLEIB $4, $1, F_4
// setup [r²,r]
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, RSAVE_3, R_3
VLVGG $1, RSAVE_4, R_4
VPDI $0, R5_1, R5SAVE_1, R5_1
VPDI $0, R5_2, R5SAVE_2, R5_2
VPDI $0, R5_3, R5SAVE_3, R5_3
VPDI $0, R5_4, R5SAVE_4, R5_4
MOVD $0, R3
BR multiply
skip:
VZERO H_0
VZERO H_1
VZERO H_2
VZERO H_3
VZERO H_4
CMPBEQ R3, $0, finish
b1:
// 1 block remaining
SUB $1, R3
VLL R3, (R2), T_0
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, T_0
VZERO T_1
EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4)
CMPBNE R3, $16, 2(PC)
VLEIB $4, $1, F_4
VLEIG $1, $1, R_0
VZERO R_1
VZERO R_2
VZERO R_3
VZERO R_4
VZERO R5_1
VZERO R5_2
VZERO R5_3
VZERO R5_4
// setup [r, 1]
VLVGG $0, RSAVE_0, R_0
VLVGG $0, RSAVE_1, R_1
VLVGG $0, RSAVE_2, R_2
VLVGG $0, RSAVE_3, R_3
VLVGG $0, RSAVE_4, R_4
VPDI $0, R5SAVE_1, R5_1, R5_1
VPDI $0, R5SAVE_2, R5_2, R5_2
VPDI $0, R5SAVE_3, R5_3, R5_3
VPDI $0, R5SAVE_4, R5_4, R5_4
MOVD $0, R3
BR multiply
TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
MOVD $x-24(SP), R1
XC $24, 0(R1), 0(R1) // clear the storage
MOVD $2, R0 // R0 is the number of double words stored -1
WORD $0xB2B01000 // STFLE 0(R1)
XOR R0, R0 // reset the value of R0
MOVBZ z-8(SP), R1
AND $0x40, R1
BEQ novector
vectorinstalled:
// check if the vector instruction has been enabled
VLEIB $0, $0xF, V16
VLGVB $0, V16, R1
CMPBNE R1, $0xF, novector
MOVB $1, ret+0(FP) // have vx
RET
novector:
MOVB $0, ret+0(FP) // no vx
RET

931
vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s generated vendored Normal file
View file

@ -0,0 +1,931 @@
// Copyright 2018 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 s390x,go1.11,!gccgo,!appengine
#include "textflag.h"
// Implementation of Poly1305 using the vector facility (vx) and the VMSL instruction.
// constants
#define EX0 V1
#define EX1 V2
#define EX2 V3
// temporaries
#define T_0 V4
#define T_1 V5
#define T_2 V6
#define T_3 V7
#define T_4 V8
#define T_5 V9
#define T_6 V10
#define T_7 V11
#define T_8 V12
#define T_9 V13
#define T_10 V14
// r**2 & r**4
#define R_0 V15
#define R_1 V16
#define R_2 V17
#define R5_1 V18
#define R5_2 V19
// key (r)
#define RSAVE_0 R7
#define RSAVE_1 R8
#define RSAVE_2 R9
#define R5SAVE_1 R10
#define R5SAVE_2 R11
// message block
#define M0 V20
#define M1 V21
#define M2 V22
#define M3 V23
#define M4 V24
#define M5 V25
// accumulator
#define H0_0 V26
#define H1_0 V27
#define H2_0 V28
#define H0_1 V29
#define H1_1 V30
#define H2_1 V31
GLOBL ·keyMask<>(SB), RODATA, $16
DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f
DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f
GLOBL ·bswapMask<>(SB), RODATA, $16
DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908
DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100
GLOBL ·constants<>(SB), RODATA, $48
// EX0
DATA ·constants<>+0(SB)/8, $0x18191a1b1c1d1e1f
DATA ·constants<>+8(SB)/8, $0x0000050403020100
// EX1
DATA ·constants<>+16(SB)/8, $0x18191a1b1c1d1e1f
DATA ·constants<>+24(SB)/8, $0x00000a0908070605
// EX2
DATA ·constants<>+32(SB)/8, $0x18191a1b1c1d1e1f
DATA ·constants<>+40(SB)/8, $0x0000000f0e0d0c0b
GLOBL ·c<>(SB), RODATA, $48
// EX0
DATA ·c<>+0(SB)/8, $0x0000050403020100
DATA ·c<>+8(SB)/8, $0x0000151413121110
// EX1
DATA ·c<>+16(SB)/8, $0x00000a0908070605
DATA ·c<>+24(SB)/8, $0x00001a1918171615
// EX2
DATA ·c<>+32(SB)/8, $0x0000000f0e0d0c0b
DATA ·c<>+40(SB)/8, $0x0000001f1e1d1c1b
GLOBL ·reduce<>(SB), RODATA, $32
// 44 bit
DATA ·reduce<>+0(SB)/8, $0x0
DATA ·reduce<>+8(SB)/8, $0xfffffffffff
// 42 bit
DATA ·reduce<>+16(SB)/8, $0x0
DATA ·reduce<>+24(SB)/8, $0x3ffffffffff
// h = (f*g) % (2**130-5) [partial reduction]
// uses T_0...T_9 temporary registers
// input: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
// output: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2
#define MULTIPLY(m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) \
\ // Eliminate the dependency for the last 2 VMSLs
VMSLG m02_0, r_2, m4_2, m4_2 \
VMSLG m13_0, r_2, m5_2, m5_2 \ // 8 VMSLs pipelined
VMSLG m02_0, r_0, m4_0, m4_0 \
VMSLG m02_1, r5_2, V0, T_0 \
VMSLG m02_0, r_1, m4_1, m4_1 \
VMSLG m02_1, r_0, V0, T_1 \
VMSLG m02_1, r_1, V0, T_2 \
VMSLG m02_2, r5_1, V0, T_3 \
VMSLG m02_2, r5_2, V0, T_4 \
VMSLG m13_0, r_0, m5_0, m5_0 \
VMSLG m13_1, r5_2, V0, T_5 \
VMSLG m13_0, r_1, m5_1, m5_1 \
VMSLG m13_1, r_0, V0, T_6 \
VMSLG m13_1, r_1, V0, T_7 \
VMSLG m13_2, r5_1, V0, T_8 \
VMSLG m13_2, r5_2, V0, T_9 \
VMSLG m02_2, r_0, m4_2, m4_2 \
VMSLG m13_2, r_0, m5_2, m5_2 \
VAQ m4_0, T_0, m02_0 \
VAQ m4_1, T_1, m02_1 \
VAQ m5_0, T_5, m13_0 \
VAQ m5_1, T_6, m13_1 \
VAQ m02_0, T_3, m02_0 \
VAQ m02_1, T_4, m02_1 \
VAQ m13_0, T_8, m13_0 \
VAQ m13_1, T_9, m13_1 \
VAQ m4_2, T_2, m02_2 \
VAQ m5_2, T_7, m13_2 \
// SQUARE uses three limbs of r and r_2*5 to output square of r
// uses T_1, T_5 and T_7 temporary registers
// input: r_0, r_1, r_2, r5_2
// temp: TEMP0, TEMP1, TEMP2
// output: p0, p1, p2
#define SQUARE(r_0, r_1, r_2, r5_2, p0, p1, p2, TEMP0, TEMP1, TEMP2) \
VMSLG r_0, r_0, p0, p0 \
VMSLG r_1, r5_2, V0, TEMP0 \
VMSLG r_2, r5_2, p1, p1 \
VMSLG r_0, r_1, V0, TEMP1 \
VMSLG r_1, r_1, p2, p2 \
VMSLG r_0, r_2, V0, TEMP2 \
VAQ TEMP0, p0, p0 \
VAQ TEMP1, p1, p1 \
VAQ TEMP2, p2, p2 \
VAQ TEMP0, p0, p0 \
VAQ TEMP1, p1, p1 \
VAQ TEMP2, p2, p2 \
// carry h0->h1->h2->h0 || h3->h4->h5->h3
// uses T_2, T_4, T_5, T_7, T_8, T_9
// t6, t7, t8, t9, t10, t11
// input: h0, h1, h2, h3, h4, h5
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11
// output: h0, h1, h2, h3, h4, h5
#define REDUCE(h0, h1, h2, h3, h4, h5, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) \
VLM (R12), t6, t7 \ // 44 and 42 bit clear mask
VLEIB $7, $0x28, t10 \ // 5 byte shift mask
VREPIB $4, t8 \ // 4 bit shift mask
VREPIB $2, t11 \ // 2 bit shift mask
VSRLB t10, h0, t0 \ // h0 byte shift
VSRLB t10, h1, t1 \ // h1 byte shift
VSRLB t10, h2, t2 \ // h2 byte shift
VSRLB t10, h3, t3 \ // h3 byte shift
VSRLB t10, h4, t4 \ // h4 byte shift
VSRLB t10, h5, t5 \ // h5 byte shift
VSRL t8, t0, t0 \ // h0 bit shift
VSRL t8, t1, t1 \ // h2 bit shift
VSRL t11, t2, t2 \ // h2 bit shift
VSRL t8, t3, t3 \ // h3 bit shift
VSRL t8, t4, t4 \ // h4 bit shift
VESLG $2, t2, t9 \ // h2 carry x5
VSRL t11, t5, t5 \ // h5 bit shift
VN t6, h0, h0 \ // h0 clear carry
VAQ t2, t9, t2 \ // h2 carry x5
VESLG $2, t5, t9 \ // h5 carry x5
VN t6, h1, h1 \ // h1 clear carry
VN t7, h2, h2 \ // h2 clear carry
VAQ t5, t9, t5 \ // h5 carry x5
VN t6, h3, h3 \ // h3 clear carry
VN t6, h4, h4 \ // h4 clear carry
VN t7, h5, h5 \ // h5 clear carry
VAQ t0, h1, h1 \ // h0->h1
VAQ t3, h4, h4 \ // h3->h4
VAQ t1, h2, h2 \ // h1->h2
VAQ t4, h5, h5 \ // h4->h5
VAQ t2, h0, h0 \ // h2->h0
VAQ t5, h3, h3 \ // h5->h3
VREPG $1, t6, t6 \ // 44 and 42 bit masks across both halves
VREPG $1, t7, t7 \
VSLDB $8, h0, h0, h0 \ // set up [h0/1/2, h3/4/5]
VSLDB $8, h1, h1, h1 \
VSLDB $8, h2, h2, h2 \
VO h0, h3, h3 \
VO h1, h4, h4 \
VO h2, h5, h5 \
VESRLG $44, h3, t0 \ // 44 bit shift right
VESRLG $44, h4, t1 \
VESRLG $42, h5, t2 \
VN t6, h3, h3 \ // clear carry bits
VN t6, h4, h4 \
VN t7, h5, h5 \
VESLG $2, t2, t9 \ // multiply carry by 5
VAQ t9, t2, t2 \
VAQ t0, h4, h4 \
VAQ t1, h5, h5 \
VAQ t2, h3, h3 \
// carry h0->h1->h2->h0
// input: h0, h1, h2
// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8
// output: h0, h1, h2
#define REDUCE2(h0, h1, h2, t0, t1, t2, t3, t4, t5, t6, t7, t8) \
VLEIB $7, $0x28, t3 \ // 5 byte shift mask
VREPIB $4, t4 \ // 4 bit shift mask
VREPIB $2, t7 \ // 2 bit shift mask
VGBM $0x003F, t5 \ // mask to clear carry bits
VSRLB t3, h0, t0 \
VSRLB t3, h1, t1 \
VSRLB t3, h2, t2 \
VESRLG $4, t5, t5 \ // 44 bit clear mask
VSRL t4, t0, t0 \
VSRL t4, t1, t1 \
VSRL t7, t2, t2 \
VESRLG $2, t5, t6 \ // 42 bit clear mask
VESLG $2, t2, t8 \
VAQ t8, t2, t2 \
VN t5, h0, h0 \
VN t5, h1, h1 \
VN t6, h2, h2 \
VAQ t0, h1, h1 \
VAQ t1, h2, h2 \
VAQ t2, h0, h0 \
VSRLB t3, h0, t0 \
VSRLB t3, h1, t1 \
VSRLB t3, h2, t2 \
VSRL t4, t0, t0 \
VSRL t4, t1, t1 \
VSRL t7, t2, t2 \
VN t5, h0, h0 \
VN t5, h1, h1 \
VESLG $2, t2, t8 \
VN t6, h2, h2 \
VAQ t0, h1, h1 \
VAQ t8, t2, t2 \
VAQ t1, h2, h2 \
VAQ t2, h0, h0 \
// expands two message blocks into the lower halfs of the d registers
// moves the contents of the d registers into upper halfs
// input: in1, in2, d0, d1, d2, d3, d4, d5
// temp: TEMP0, TEMP1, TEMP2, TEMP3
// output: d0, d1, d2, d3, d4, d5
#define EXPACC(in1, in2, d0, d1, d2, d3, d4, d5, TEMP0, TEMP1, TEMP2, TEMP3) \
VGBM $0xff3f, TEMP0 \
VGBM $0xff1f, TEMP1 \
VESLG $4, d1, TEMP2 \
VESLG $4, d4, TEMP3 \
VESRLG $4, TEMP0, TEMP0 \
VPERM in1, d0, EX0, d0 \
VPERM in2, d3, EX0, d3 \
VPERM in1, d2, EX2, d2 \
VPERM in2, d5, EX2, d5 \
VPERM in1, TEMP2, EX1, d1 \
VPERM in2, TEMP3, EX1, d4 \
VN TEMP0, d0, d0 \
VN TEMP0, d3, d3 \
VESRLG $4, d1, d1 \
VESRLG $4, d4, d4 \
VN TEMP1, d2, d2 \
VN TEMP1, d5, d5 \
VN TEMP0, d1, d1 \
VN TEMP0, d4, d4 \
// expands one message block into the lower halfs of the d registers
// moves the contents of the d registers into upper halfs
// input: in, d0, d1, d2
// temp: TEMP0, TEMP1, TEMP2
// output: d0, d1, d2
#define EXPACC2(in, d0, d1, d2, TEMP0, TEMP1, TEMP2) \
VGBM $0xff3f, TEMP0 \
VESLG $4, d1, TEMP2 \
VGBM $0xff1f, TEMP1 \
VPERM in, d0, EX0, d0 \
VESRLG $4, TEMP0, TEMP0 \
VPERM in, d2, EX2, d2 \
VPERM in, TEMP2, EX1, d1 \
VN TEMP0, d0, d0 \
VN TEMP1, d2, d2 \
VESRLG $4, d1, d1 \
VN TEMP0, d1, d1 \
// pack h2:h0 into h1:h0 (no carry)
// input: h0, h1, h2
// output: h0, h1, h2
#define PACK(h0, h1, h2) \
VMRLG h1, h2, h2 \ // copy h1 to upper half h2
VESLG $44, h1, h1 \ // shift limb 1 44 bits, leaving 20
VO h0, h1, h0 \ // combine h0 with 20 bits from limb 1
VESRLG $20, h2, h1 \ // put top 24 bits of limb 1 into h1
VLEIG $1, $0, h1 \ // clear h2 stuff from lower half of h1
VO h0, h1, h0 \ // h0 now has 88 bits (limb 0 and 1)
VLEIG $0, $0, h2 \ // clear upper half of h2
VESRLG $40, h2, h1 \ // h1 now has upper two bits of result
VLEIB $7, $88, h1 \ // for byte shift (11 bytes)
VSLB h1, h2, h2 \ // shift h2 11 bytes to the left
VO h0, h2, h0 \ // combine h0 with 20 bits from limb 1
VLEIG $0, $0, h1 \ // clear upper half of h1
// if h > 2**130-5 then h -= 2**130-5
// input: h0, h1
// temp: t0, t1, t2
// output: h0
#define MOD(h0, h1, t0, t1, t2) \
VZERO t0 \
VLEIG $1, $5, t0 \
VACCQ h0, t0, t1 \
VAQ h0, t0, t0 \
VONE t2 \
VLEIG $1, $-4, t2 \
VAQ t2, t1, t1 \
VACCQ h1, t1, t1 \
VONE t2 \
VAQ t2, t1, t1 \
VN h0, t1, t2 \
VNC t0, t1, t1 \
VO t1, t2, h0 \
// func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]key)
TEXT ·poly1305vmsl(SB), $0-32
// This code processes 6 + up to 4 blocks (32 bytes) per iteration
// using the algorithm described in:
// NEON crypto, Daniel J. Bernstein & Peter Schwabe
// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
// And as moddified for VMSL as described in
// Accelerating Poly1305 Cryptographic Message Authentication on the z14
// O'Farrell et al, CASCON 2017, p48-55
// https://ibm.ent.box.com/s/jf9gedj0e9d2vjctfyh186shaztavnht
LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key
VZERO V0 // c
// load EX0, EX1 and EX2
MOVD $·constants<>(SB), R5
VLM (R5), EX0, EX2 // c
// setup r
VL (R4), T_0
MOVD $·keyMask<>(SB), R6
VL (R6), T_1
VN T_0, T_1, T_0
VZERO T_2 // limbs for r
VZERO T_3
VZERO T_4
EXPACC2(T_0, T_2, T_3, T_4, T_1, T_5, T_7)
// T_2, T_3, T_4: [0, r]
// setup r*20
VLEIG $0, $0, T_0
VLEIG $1, $20, T_0 // T_0: [0, 20]
VZERO T_5
VZERO T_6
VMSLG T_0, T_3, T_5, T_5
VMSLG T_0, T_4, T_6, T_6
// store r for final block in GR
VLGVG $1, T_2, RSAVE_0 // c
VLGVG $1, T_3, RSAVE_1 // c
VLGVG $1, T_4, RSAVE_2 // c
VLGVG $1, T_5, R5SAVE_1 // c
VLGVG $1, T_6, R5SAVE_2 // c
// initialize h
VZERO H0_0
VZERO H1_0
VZERO H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
// initialize pointer for reduce constants
MOVD $·reduce<>(SB), R12
// calculate r**2 and 20*(r**2)
VZERO R_0
VZERO R_1
VZERO R_2
SQUARE(T_2, T_3, T_4, T_6, R_0, R_1, R_2, T_1, T_5, T_7)
REDUCE2(R_0, R_1, R_2, M0, M1, M2, M3, M4, R5_1, R5_2, M5, T_1)
VZERO R5_1
VZERO R5_2
VMSLG T_0, R_1, R5_1, R5_1
VMSLG T_0, R_2, R5_2, R5_2
// skip r**4 calculation if 3 blocks or less
CMPBLE R3, $48, b4
// calculate r**4 and 20*(r**4)
VZERO T_8
VZERO T_9
VZERO T_10
SQUARE(R_0, R_1, R_2, R5_2, T_8, T_9, T_10, T_1, T_5, T_7)
REDUCE2(T_8, T_9, T_10, M0, M1, M2, M3, M4, T_2, T_3, M5, T_1)
VZERO T_2
VZERO T_3
VMSLG T_0, T_9, T_2, T_2
VMSLG T_0, T_10, T_3, T_3
// put r**2 to the right and r**4 to the left of R_0, R_1, R_2
VSLDB $8, T_8, T_8, T_8
VSLDB $8, T_9, T_9, T_9
VSLDB $8, T_10, T_10, T_10
VSLDB $8, T_2, T_2, T_2
VSLDB $8, T_3, T_3, T_3
VO T_8, R_0, R_0
VO T_9, R_1, R_1
VO T_10, R_2, R_2
VO T_2, R5_1, R5_1
VO T_3, R5_2, R5_2
CMPBLE R3, $80, load // less than or equal to 5 blocks in message
// 6(or 5+1) blocks
SUB $81, R3
VLM (R2), M0, M4
VLL R3, 80(R2), M5
ADD $1, R3
MOVBZ $1, R0
CMPBGE R3, $16, 2(PC)
VLVGB R3, R0, M5
MOVD $96(R2), R2
EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
EXPACC(M2, M3, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
VLEIB $2, $1, H2_0
VLEIB $2, $1, H2_1
VLEIB $10, $1, H2_0
VLEIB $10, $1, H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO T_4
VZERO T_10
EXPACC(M4, M5, M0, M1, M2, M3, T_4, T_10, T_0, T_1, T_2, T_3)
VLR T_4, M4
VLEIB $10, $1, M2
CMPBLT R3, $16, 2(PC)
VLEIB $10, $1, T_10
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
SUB $16, R3
CMPBLE R3, $0, square
load:
// load EX0, EX1 and EX2
MOVD $·c<>(SB), R5
VLM (R5), EX0, EX2
loop:
CMPBLE R3, $64, add // b4 // last 4 or less blocks left
// next 4 full blocks
VLM (R2), M2, M5
SUB $64, R3
MOVD $64(R2), R2
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, T_0, T_1, T_3, T_4, T_5, T_2, T_7, T_8, T_9)
// expacc in-lined to create [m2, m3] limbs
VGBM $0x3f3f, T_0 // 44 bit clear mask
VGBM $0x1f1f, T_1 // 40 bit clear mask
VPERM M2, M3, EX0, T_3
VESRLG $4, T_0, T_0 // 44 bit clear mask ready
VPERM M2, M3, EX1, T_4
VPERM M2, M3, EX2, T_5
VN T_0, T_3, T_3
VESRLG $4, T_4, T_4
VN T_1, T_5, T_5
VN T_0, T_4, T_4
VMRHG H0_1, T_3, H0_0
VMRHG H1_1, T_4, H1_0
VMRHG H2_1, T_5, H2_0
VMRLG H0_1, T_3, H0_1
VMRLG H1_1, T_4, H1_1
VMRLG H2_1, T_5, H2_1
VLEIB $10, $1, H2_0
VLEIB $10, $1, H2_1
VPERM M4, M5, EX0, T_3
VPERM M4, M5, EX1, T_4
VPERM M4, M5, EX2, T_5
VN T_0, T_3, T_3
VESRLG $4, T_4, T_4
VN T_1, T_5, T_5
VN T_0, T_4, T_4
VMRHG V0, T_3, M0
VMRHG V0, T_4, M1
VMRHG V0, T_5, M2
VMRLG V0, T_3, M3
VMRLG V0, T_4, M4
VMRLG V0, T_5, M5
VLEIB $10, $1, M2
VLEIB $10, $1, M5
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
CMPBNE R3, $0, loop
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
// load EX0, EX1, EX2
MOVD $·constants<>(SB), R5
VLM (R5), EX0, EX2
// sum vectors
VAQ H0_0, H0_1, H0_0
VAQ H1_0, H1_1, H1_0
VAQ H2_0, H2_1, H2_0
// h may be >= 2*(2**130-5) so we need to reduce it again
// M0...M4 are used as temps here
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
next: // carry h1->h2
VLEIB $7, $0x28, T_1
VREPIB $4, T_2
VGBM $0x003F, T_3
VESRLG $4, T_3
// byte shift
VSRLB T_1, H1_0, T_4
// bit shift
VSRL T_2, T_4, T_4
// clear h1 carry bits
VN T_3, H1_0, H1_0
// add carry
VAQ T_4, H2_0, H2_0
// h is now < 2*(2**130-5)
// pack h into h1 (hi) and h0 (lo)
PACK(H0_0, H1_0, H2_0)
// if h > 2**130-5 then h -= 2**130-5
MOD(H0_0, H1_0, T_0, T_1, T_2)
// h += s
MOVD $·bswapMask<>(SB), R5
VL (R5), T_1
VL 16(R4), T_0
VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big)
VAQ T_0, H0_0, H0_0
VPERM H0_0, H0_0, T_1, H0_0 // reverse bytes (to little)
VST H0_0, (R1)
RET
add:
// load EX0, EX1, EX2
MOVD $·constants<>(SB), R5
VLM (R5), EX0, EX2
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
CMPBLE R3, $64, b4
b4:
CMPBLE R3, $48, b3 // 3 blocks or less
// 4(3+1) blocks remaining
SUB $49, R3
VLM (R2), M0, M2
VLL R3, 48(R2), M3
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M3
MOVD $64(R2), R2
EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3)
VLEIB $10, $1, H2_0
VLEIB $10, $1, H2_1
VZERO M0
VZERO M1
VZERO M4
VZERO M5
VZERO T_4
VZERO T_10
EXPACC(M2, M3, M0, M1, M4, M5, T_4, T_10, T_0, T_1, T_2, T_3)
VLR T_4, M2
VLEIB $10, $1, M4
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, T_10
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M4, M5, M2, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
SUB $16, R3
CMPBLE R3, $0, square // this condition must always hold true!
b3:
CMPBLE R3, $32, b2
// 3 blocks remaining
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// H*[r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, T_10, M5)
SUB $33, R3
VLM (R2), M0, M1
VLL R3, 32(R2), M2
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M2
// H += m0
VZERO T_1
VZERO T_2
VZERO T_3
EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)
VLEIB $10, $1, T_3
VAG H0_0, T_1, H0_0
VAG H1_0, T_2, H1_0
VAG H2_0, T_3, H2_0
VZERO M0
VZERO M3
VZERO M4
VZERO M5
VZERO T_10
// (H+m0)*r
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M3, M4, M5, V0, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_10, H0_1, H1_1, H2_1, T_9)
// H += m1
VZERO V0
VZERO T_1
VZERO T_2
VZERO T_3
EXPACC2(M1, T_1, T_2, T_3, T_4, T_5, T_6)
VLEIB $10, $1, T_3
VAQ H0_0, T_1, H0_0
VAQ H1_0, T_2, H1_0
VAQ H2_0, T_3, H2_0
REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10)
// [H, m2] * [r**2, r]
EXPACC2(M2, H0_0, H1_0, H2_0, T_1, T_2, T_3)
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, H2_0
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, M5, T_10)
SUB $16, R3
CMPBLE R3, $0, next // this condition must always hold true!
b2:
CMPBLE R3, $16, b1
// 2 blocks remaining
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// H*[r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9)
VMRHG V0, H0_1, H0_0
VMRHG V0, H1_1, H1_0
VMRHG V0, H2_1, H2_0
VMRLG V0, H0_1, H0_1
VMRLG V0, H1_1, H1_1
VMRLG V0, H2_1, H2_1
// move h to the left and 0s at the right
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
// get message blocks and append 1 to start
SUB $17, R3
VL (R2), M0
VLL R3, 16(R2), M1
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M1
VZERO T_6
VZERO T_7
VZERO T_8
EXPACC2(M0, T_6, T_7, T_8, T_1, T_2, T_3)
EXPACC2(M1, T_6, T_7, T_8, T_1, T_2, T_3)
VLEIB $2, $1, T_8
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, T_8
// add [m0, m1] to h
VAG H0_0, T_6, H0_0
VAG H1_0, T_7, H1_0
VAG H2_0, T_8, H2_0
VZERO M2
VZERO M3
VZERO M4
VZERO M5
VZERO T_10
VZERO M0
// at this point R_0 .. R5_2 look like [r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M2, M3, M4, M5, T_10, M0, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M2, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10)
SUB $16, R3, R3
CMPBLE R3, $0, next
b1:
CMPBLE R3, $0, next
// 1 block remaining
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// H*[r**2, r]
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
// set up [0, m0] limbs
SUB $1, R3
VLL R3, (R2), M0
ADD $1, R3
MOVBZ $1, R0
CMPBEQ R3, $16, 2(PC)
VLVGB R3, R0, M0
VZERO T_1
VZERO T_2
VZERO T_3
EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)// limbs: [0, m]
CMPBNE R3, $16, 2(PC)
VLEIB $10, $1, T_3
// h+m0
VAQ H0_0, T_1, H0_0
VAQ H1_0, T_2, H1_0
VAQ H2_0, T_3, H2_0
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
BR next
square:
// setup [r²,r]
VSLDB $8, R_0, R_0, R_0
VSLDB $8, R_1, R_1, R_1
VSLDB $8, R_2, R_2, R_2
VSLDB $8, R5_1, R5_1, R5_1
VSLDB $8, R5_2, R5_2, R5_2
VLVGG $1, RSAVE_0, R_0
VLVGG $1, RSAVE_1, R_1
VLVGG $1, RSAVE_2, R_2
VLVGG $1, R5SAVE_1, R5_1
VLVGG $1, R5SAVE_2, R5_2
// setup [h0, h1]
VSLDB $8, H0_0, H0_0, H0_0
VSLDB $8, H1_0, H1_0, H1_0
VSLDB $8, H2_0, H2_0, H2_0
VO H0_1, H0_0, H0_0
VO H1_1, H1_0, H1_0
VO H2_1, H2_0, H2_0
VZERO H0_1
VZERO H1_1
VZERO H2_1
VZERO M0
VZERO M1
VZERO M2
VZERO M3
VZERO M4
VZERO M5
// (h0*r**2) + (h1*r)
MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9)
REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5)
BR next
TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1
MOVD $x-24(SP), R1
XC $24, 0(R1), 0(R1) // clear the storage
MOVD $2, R0 // R0 is the number of double words stored -1
WORD $0xB2B01000 // STFLE 0(R1)
XOR R0, R0 // reset the value of R0
MOVBZ z-8(SP), R1
AND $0x01, R1
BEQ novmsl
vectorinstalled:
// check if the vector instruction has been enabled
VLEIB $0, $0xF, V16
VLGVB $0, V16, R1
CMPBNE R1, $0xF, novmsl
MOVB $1, ret+0(FP) // have vx
RET
novmsl:
MOVB $0, ret+0(FP) // no vx
RET

2943
vendor/golang.org/x/crypto/poly1305/vectors_test.go generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -24,6 +24,7 @@ package salsa20 // import "golang.org/x/crypto/salsa20"
// TODO(agl): implement XORKeyStream12 and XORKeyStream8 - the reduced round variants of Salsa20.
import (
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/salsa20/salsa"
)
@ -32,7 +33,10 @@ import (
// be either 8 or 24 bytes long.
func XORKeyStream(out, in []byte, nonce []byte, key *[32]byte) {
if len(out) < len(in) {
in = in[:len(out)]
panic("salsa20: output smaller than input")
}
if subtle.InexactOverlap(out[:len(in)], in) {
panic("salsa20: invalid buffer overlap")
}
var subNonce [16]byte

View file

@ -19,6 +19,8 @@ import (
type Client struct {
Conn
handleForwardsOnce sync.Once // guards calling (*Client).handleForwards
forwards forwardList // forwarded tcpip connections from the remote side
mu sync.Mutex
channelHandlers map[string]chan NewChannel
@ -60,8 +62,6 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
conn.Wait()
conn.forwards.closeAll()
}()
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
return conn
}

View file

@ -32,6 +32,7 @@ type streamLocalChannelForwardMsg struct {
// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
c.handleForwardsOnce.Do(c.handleForwards)
m := streamLocalChannelForwardMsg{
socketPath,
}

View file

@ -90,10 +90,19 @@ type channelForwardMsg struct {
rport uint32
}
// handleForwards starts goroutines handling forwarded connections.
// It's called on first use by (*Client).ListenTCP to not launch
// goroutines until needed.
func (c *Client) handleForwards() {
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip"))
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
}
// ListenTCP requests the remote peer open a listening socket
// on laddr. Incoming connections will be available by calling
// Accept on the returned net.Listener.
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
c.handleForwardsOnce.Do(c.handleForwards)
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
return c.autoPortListenWorkaround(laddr)
}

View file

@ -2,12 +2,15 @@
// 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 windows plan9 solaris
package terminal
import (
"bytes"
"io"
"os"
"runtime"
"testing"
)
@ -324,6 +327,11 @@ func TestMakeRawState(t *testing.T) {
if err != nil {
t.Fatalf("failed to get terminal state from GetState: %s", err)
}
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
t.Skip("MakeRaw not allowed on iOS; skipping test")
}
defer Restore(fd, st)
raw, err := MakeRaw(fd)
if err != nil {

View file

@ -25,6 +25,8 @@ import (
"crypto/cipher"
"encoding/binary"
"errors"
"golang.org/x/crypto/internal/subtle"
)
// Cipher contains an expanded key structure. It doesn't contain mutable state
@ -64,6 +66,9 @@ func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
if len(plaintext)%blockSize != 0 {
panic("xts: plaintext is not a multiple of the block size")
}
if subtle.InexactOverlap(ciphertext[:len(plaintext)], plaintext) {
panic("xts: invalid buffer overlap")
}
var tweak [blockSize]byte
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
@ -95,6 +100,9 @@ func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
if len(ciphertext)%blockSize != 0 {
panic("xts: ciphertext is not a multiple of the block size")
}
if subtle.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) {
panic("xts: invalid buffer overlap")
}
var tweak [blockSize]byte
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)

4154
vendor/golang.org/x/net/html/entity.go generated vendored

File diff suppressed because it is too large Load diff

View file

@ -589,20 +589,20 @@ func TestConvertNewlines(t *testing.T) {
"Mac\rDOS\r\nUnix\n": "Mac\nDOS\nUnix\n",
"Unix\nMac\rDOS\r\n": "Unix\nMac\nDOS\n",
"DOS\r\nDOS\r\nDOS\r\n": "DOS\nDOS\nDOS\n",
"": "",
"\n": "\n",
"\n\r": "\n\n",
"\r": "\n",
"\r\n": "\n",
"\r\n\n": "\n\n",
"\r\n\r": "\n\n",
"\r\n\r\n": "\n\n",
"\r\r": "\n\n",
"\r\r\n": "\n\n",
"\r\r\n\n": "\n\n\n",
"\r\r\r\n": "\n\n\n",
"\r \n": "\n \n",
"xyz": "xyz",
"": "",
"\n": "\n",
"\n\r": "\n\n",
"\r": "\n",
"\r\n": "\n",
"\r\n\n": "\n\n",
"\r\n\r": "\n\n",
"\r\n\r\n": "\n\n",
"\r\r": "\n\n",
"\r\r\n": "\n\n",
"\r\r\n\n": "\n\n\n",
"\r\r\r\n": "\n\n\n",
"\r \n": "\n \n",
"xyz": "xyz",
}
for in, want := range testCases {
if got := string(convertNewlines([]byte(in))); got != want {

View file

@ -2,12 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package httplex contains rules around lexical matters of various
// HTTP-related specifications.
//
// This package is shared by the standard library (which vendors it)
// and x/net/http2. It comes with no API stability promise.
package httplex
package httpguts
import (
"net"

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package httplex
package httpguts
import (
"testing"

View file

@ -14,8 +14,8 @@ import (
"strings"
"sync"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/lex/httplex"
)
const frameHeaderLen = 9
@ -1462,7 +1462,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
if VerboseLogs && fr.logReads {
fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
}
if !httplex.ValidHeaderFieldValue(hf.Value) {
if !httpguts.ValidHeaderFieldValue(hf.Value) {
invalid = headerFieldValueError(hf.Value)
}
isPseudo := strings.HasPrefix(hf.Name, ":")

View file

@ -389,6 +389,12 @@ func (d *Decoder) callEmit(hf HeaderField) error {
// (same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseDynamicTableSizeUpdate() error {
// RFC 7541, sec 4.2: This dynamic table size update MUST occur at the
// beginning of the first header block following the change to the dynamic table size.
if d.dynTab.size > 0 {
return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
}
buf := d.buf
size, buf, err := readVarInt(5, buf)
if err != nil {

View file

@ -720,3 +720,22 @@ func TestSaveBufLimit(t *testing.T) {
t.Fatalf("Write error = %v; want ErrStringLength", err)
}
}
func TestDynamicSizeUpdate(t *testing.T) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
enc.SetMaxDynamicTableSize(255)
enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
d := NewDecoder(4096, nil)
_, err := d.DecodeFull(buf.Bytes())
if err != nil {
t.Fatalf("unexpected error: got = %v", err)
}
// must fail since the dynamic table update must be at the beginning
_, err = d.DecodeFull(buf.Bytes())
if err == nil {
t.Fatalf("dynamic table size update not at the beginning of a header block")
}
}

View file

@ -29,7 +29,7 @@ import (
"strings"
"sync"
"golang.org/x/net/lex/httplex"
"golang.org/x/net/http/httpguts"
)
var (
@ -179,7 +179,7 @@ var (
)
// validWireHeaderFieldName reports whether v is a valid header field
// name (key). See httplex.ValidHeaderName for the base rules.
// name (key). See httpguts.ValidHeaderName for the base rules.
//
// Further, http2 says:
// "Just as in HTTP/1.x, header field names are strings of ASCII
@ -191,7 +191,7 @@ func validWireHeaderFieldName(v string) bool {
return false
}
for _, r := range v {
if !httplex.IsTokenRune(r) {
if !httpguts.IsTokenRune(r) {
return false
}
if 'A' <= r && r <= 'Z' {

View file

@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"testing"
"time"
"golang.org/x/net/http2/hpack"
)
@ -197,3 +198,30 @@ func TestSorterPoolAllocs(t *testing.T) {
t.Logf("Keys allocs = %v; want <1", allocs)
}
}
// waitCondition reports whether fn eventually returned true,
// checking immediately and then every checkEvery amount,
// until waitFor has elapsed, at which point it returns false.
func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
deadline := time.Now().Add(waitFor)
for time.Now().Before(deadline) {
if fn() {
return true
}
time.Sleep(checkEvery)
}
return false
}
// waitErrCondition is like waitCondition but with errors instead of bools.
func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
deadline := time.Now().Add(waitFor)
var err error
for time.Now().Before(deadline) {
if err = fn(); err == nil {
return nil
}
time.Sleep(checkEvery)
}
return err
}

View file

@ -1608,7 +1608,10 @@ func (sc *serverConn) processData(f *DataFrame) error {
// Sender sending more than they'd declared?
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
return streamError(id, ErrCodeStreamClosed)
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
// value of a content-length header field does not equal the sum of the
// DATA frame payload lengths that form the body.
return streamError(id, ErrCodeProtocol)
}
if f.Length > 0 {
// Check whether the client has flow control quota.

View file

@ -3759,3 +3759,22 @@ func TestIssue20704Race(t *testing.T) {
resp.Body.Close()
}
}
func TestServer_Rejects_TooSmall(t *testing.T) {
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
return nil
}, func(st *serverTester) {
st.writeHeaders(HeadersFrameParam{
StreamID: 1, // clients send odd numbers
BlockFragment: st.encodeHeader(
":method", "POST",
"content-length", "4",
),
EndStream: false, // to say DATA frames are coming
EndHeaders: true,
})
st.writeData(1, true, []byte("12345"))
st.wantRSTStream(1, ErrCodeProtocol)
})
}

View file

@ -27,9 +27,9 @@ import (
"sync"
"time"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/idna"
"golang.org/x/net/lex/httplex"
)
const (
@ -567,6 +567,10 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
// henc in response to SETTINGS frames?
cc.henc = hpack.NewEncoder(&cc.hbuf)
if t.AllowHTTP {
cc.nextStreamID = 3
}
if cs, ok := c.(connectionStater); ok {
state := cs.ConnectionState()
cc.tlsState = &state
@ -1177,7 +1181,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
if host == "" {
host = req.URL.Host
}
host, err := httplex.PunycodeHostPort(host)
host, err := httpguts.PunycodeHostPort(host)
if err != nil {
return nil, err
}
@ -1202,11 +1206,11 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
// potentially pollute our hpack state. (We want to be able to
// continue to reuse the hpack encoder for future requests)
for k, vv := range req.Header {
if !httplex.ValidHeaderFieldName(k) {
if !httpguts.ValidHeaderFieldName(k) {
return nil, fmt.Errorf("invalid HTTP header name %q", k)
}
for _, v := range vv {
if !httplex.ValidHeaderFieldValue(v) {
if !httpguts.ValidHeaderFieldValue(v) {
return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
}
}
@ -2247,7 +2251,7 @@ func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s body
}
s.delay = t.expectContinueTimeout()
if s.delay == 0 ||
!httplex.HeaderValuesContainsToken(
!httpguts.HeaderValuesContainsToken(
cs.req.Header["Expect"],
"100-continue") {
return
@ -2302,5 +2306,5 @@ func (s bodyWriterState) scheduleBodyWrite() {
// isConnectionCloseRequest reports whether req should use its own
// connection for a single request and then close the connection.
func isConnectionCloseRequest(req *http.Request) bool {
return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close")
}

View file

@ -2394,11 +2394,12 @@ func TestTransportHandlerBodyClose(t *testing.T) {
}
tr.CloseIdleConnections()
gd := runtime.NumGoroutine() - g0
if gd > numReq/2 {
if !waitCondition(5*time.Second, 100*time.Millisecond, func() bool {
gd := runtime.NumGoroutine() - g0
return gd < numReq/2
}) {
t.Errorf("appeared to leak goroutines")
}
}
// https://golang.org/issue/15930

View file

@ -11,8 +11,8 @@ import (
"net/http"
"net/url"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/lex/httplex"
)
// writeFramer is implemented by any type that is used to write frames.
@ -350,7 +350,7 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
}
isTE := k == "transfer-encoding"
for _, v := range vv {
if !httplex.ValidHeaderFieldValue(v) {
if !httpguts.ValidHeaderFieldValue(v) {
// TODO: return an error? golang.org/issue/14048
// For now just omit it.
continue

View file

@ -6,7 +6,7 @@ package icmp
import "encoding/binary"
// A MPLSLabel represents a MPLS label stack entry.
// MPLSLabel represents an MPLS label stack entry.
type MPLSLabel struct {
Label int // label value
TC int // traffic class; formerly experimental use
@ -19,7 +19,7 @@ const (
typeIncomingMPLSLabelStack = 1
)
// A MPLSLabelStack represents a MPLS label stack.
// MPLSLabelStack represents an MPLS label stack.
type MPLSLabelStack struct {
Class int // extension object class number
Type int // extension object sub-type

View file

@ -4,38 +4,34 @@
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
package iana // import "golang.org/x/net/internal/iana"
// Differentiated Services Field Codepoints (DSCP), Updated: 2017-05-12
// Differentiated Services Field Codepoints (DSCP), Updated: 2018-05-04
const (
DiffServCS0 = 0x0 // CS0
DiffServCS1 = 0x20 // CS1
DiffServCS2 = 0x40 // CS2
DiffServCS3 = 0x60 // CS3
DiffServCS4 = 0x80 // CS4
DiffServCS5 = 0xa0 // CS5
DiffServCS6 = 0xc0 // CS6
DiffServCS7 = 0xe0 // CS7
DiffServAF11 = 0x28 // AF11
DiffServAF12 = 0x30 // AF12
DiffServAF13 = 0x38 // AF13
DiffServAF21 = 0x48 // AF21
DiffServAF22 = 0x50 // AF22
DiffServAF23 = 0x58 // AF23
DiffServAF31 = 0x68 // AF31
DiffServAF32 = 0x70 // AF32
DiffServAF33 = 0x78 // AF33
DiffServAF41 = 0x88 // AF41
DiffServAF42 = 0x90 // AF42
DiffServAF43 = 0x98 // AF43
DiffServEF = 0xb8 // EF
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
)
// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06
const (
NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
CongestionExperienced = 0x3 // CE (Congestion Experienced)
DiffServCS0 = 0x00 // CS0
DiffServCS1 = 0x20 // CS1
DiffServCS2 = 0x40 // CS2
DiffServCS3 = 0x60 // CS3
DiffServCS4 = 0x80 // CS4
DiffServCS5 = 0xa0 // CS5
DiffServCS6 = 0xc0 // CS6
DiffServCS7 = 0xe0 // CS7
DiffServAF11 = 0x28 // AF11
DiffServAF12 = 0x30 // AF12
DiffServAF13 = 0x38 // AF13
DiffServAF21 = 0x48 // AF21
DiffServAF22 = 0x50 // AF22
DiffServAF23 = 0x58 // AF23
DiffServAF31 = 0x68 // AF31
DiffServAF32 = 0x70 // AF32
DiffServAF33 = 0x78 // AF33
DiffServAF41 = 0x88 // AF41
DiffServAF42 = 0x90 // AF42
DiffServAF43 = 0x98 // AF43
DiffServEF = 0xb8 // EF
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
NotECNTransport = 0x00 // Not-ECT (Not ECN-Capable Transport)
ECNTransport1 = 0x01 // ECT(1) (ECN-Capable Transport(1))
ECNTransport0 = 0x02 // ECT(0) (ECN-Capable Transport(0))
CongestionExperienced = 0x03 // CE (Congestion Experienced)
)
// Protocol Numbers, Updated: 2017-10-13
@ -179,7 +175,7 @@ const (
ProtocolReserved = 255 // Reserved
)
// Address Family Numbers, Updated: 2016-10-25
// Address Family Numbers, Updated: 2018-04-02
const (
AddrFamilyIPv4 = 1 // IP (IP version 4)
AddrFamilyIPv6 = 2 // IP6 (IP version 6)

View file

@ -31,16 +31,12 @@ var registries = []struct {
"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
parseDSCPRegistry,
},
{
"https://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml",
parseTOSTCByte,
},
{
"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
parseProtocolNumbers,
},
{
"http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
"https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
parseAddrFamilyNumbers,
},
}
@ -85,31 +81,39 @@ func parseDSCPRegistry(w io.Writer, r io.Reader) error {
if err := dec.Decode(&dr); err != nil {
return err
}
drs := dr.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
fmt.Fprintf(w, "const (\n")
for _, dr := range drs {
fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value)
for _, dr := range dr.escapeDSCP() {
fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value)
fmt.Fprintf(w, "// %s\n", dr.OrigName)
}
for _, er := range dr.escapeECN() {
fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value)
fmt.Fprintf(w, "// %s\n", er.OrigDescr)
}
fmt.Fprintf(w, ")\n")
return nil
}
type dscpRegistry struct {
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
Note string `xml:"note"`
RegTitle string `xml:"registry>title"`
PoolRecords []struct {
Name string `xml:"name"`
Space string `xml:"space"`
} `xml:"registry>record"`
Records []struct {
Name string `xml:"name"`
Space string `xml:"space"`
} `xml:"registry>registry>record"`
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
Note string `xml:"note"`
Registries []struct {
Title string `xml:"title"`
Registries []struct {
Title string `xml:"title"`
Records []struct {
Name string `xml:"name"`
Space string `xml:"space"`
} `xml:"record"`
} `xml:"registry"`
Records []struct {
Value string `xml:"value"`
Descr string `xml:"description"`
} `xml:"record"`
} `xml:"registry"`
}
type canonDSCPRecord struct {
@ -118,92 +122,84 @@ type canonDSCPRecord struct {
Value int
}
func (drr *dscpRegistry) escape() []canonDSCPRecord {
drs := make([]canonDSCPRecord, len(drr.Records))
sr := strings.NewReplacer(
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, dr := range drr.Records {
s := strings.TrimSpace(dr.Name)
drs[i].OrigName = s
drs[i].Name = sr.Replace(s)
n, err := strconv.ParseUint(dr.Space, 2, 8)
if err != nil {
func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord {
var drs []canonDSCPRecord
for _, preg := range drr.Registries {
if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") {
continue
}
drs[i].Value = int(n) << 2
for _, reg := range preg.Registries {
if !strings.Contains(reg.Title, "Pool 1 Codepoints") {
continue
}
drs = make([]canonDSCPRecord, len(reg.Records))
sr := strings.NewReplacer(
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, dr := range reg.Records {
s := strings.TrimSpace(dr.Name)
drs[i].OrigName = s
drs[i].Name = sr.Replace(s)
n, err := strconv.ParseUint(dr.Space, 2, 8)
if err != nil {
continue
}
drs[i].Value = int(n) << 2
}
}
}
return drs
}
func parseTOSTCByte(w io.Writer, r io.Reader) error {
dec := xml.NewDecoder(r)
var ttb tosTCByte
if err := dec.Decode(&ttb); err != nil {
return err
}
trs := ttb.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated)
fmt.Fprintf(w, "const (\n")
for _, tr := range trs {
fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value)
fmt.Fprintf(w, "// %s\n", tr.OrigKeyword)
}
fmt.Fprintf(w, ")\n")
return nil
type canonECNRecord struct {
OrigDescr string
Descr string
Value int
}
type tosTCByte struct {
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
Note string `xml:"note"`
RegTitle string `xml:"registry>title"`
Records []struct {
Binary string `xml:"binary"`
Keyword string `xml:"keyword"`
} `xml:"registry>record"`
}
type canonTOSTCByteRecord struct {
OrigKeyword string
Keyword string
Value int
}
func (ttb *tosTCByte) escape() []canonTOSTCByteRecord {
trs := make([]canonTOSTCByteRecord, len(ttb.Records))
sr := strings.NewReplacer(
"Capable", "",
"(", "",
")", "",
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, tr := range ttb.Records {
s := strings.TrimSpace(tr.Keyword)
trs[i].OrigKeyword = s
ss := strings.Split(s, " ")
if len(ss) > 1 {
trs[i].Keyword = strings.Join(ss[1:], " ")
} else {
trs[i].Keyword = ss[0]
}
trs[i].Keyword = sr.Replace(trs[i].Keyword)
n, err := strconv.ParseUint(tr.Binary, 2, 8)
if err != nil {
func (drr *dscpRegistry) escapeECN() []canonECNRecord {
var ers []canonECNRecord
for _, reg := range drr.Registries {
if !strings.Contains(reg.Title, "ECN Field") {
continue
}
trs[i].Value = int(n)
ers = make([]canonECNRecord, len(reg.Records))
sr := strings.NewReplacer(
"Capable", "",
"Not-ECT", "",
"ECT(1)", "",
"ECT(0)", "",
"CE", "",
"(", "",
")", "",
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, er := range reg.Records {
s := strings.TrimSpace(er.Descr)
ers[i].OrigDescr = s
ss := strings.Split(s, " ")
if len(ss) > 1 {
ers[i].Descr = strings.Join(ss[1:], " ")
} else {
ers[i].Descr = ss[0]
}
ers[i].Descr = sr.Replace(er.Descr)
n, err := strconv.ParseUint(er.Value, 2, 8)
if err != nil {
continue
}
ers[i].Value = int(n)
}
}
return trs
return ers
}
func parseProtocolNumbers(w io.Writer, r io.Reader) error {

View file

@ -17,19 +17,11 @@ import (
"golang.org/x/net/internal/sockstest"
)
const (
targetNetwork = "tcp6"
targetHostname = "fqdn.doesnotexist"
targetHostIP = "2001:db8::1"
targetPort = "5963"
)
func TestDial(t *testing.T) {
t.Run("Connect", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
@ -41,21 +33,45 @@ func TestDial(t *testing.T) {
Username: "username",
Password: "password",
}).Authenticate
c, err := d.Dial(targetNetwork, net.JoinHostPort(targetHostIP, targetPort))
if err == nil {
c.(*socks.Conn).BoundAddr()
c.Close()
}
c, err := d.DialContext(context.Background(), ss.TargetAddr().Network(), ss.TargetAddr().String())
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
c.(*socks.Conn).BoundAddr()
c.Close()
})
t.Run("ConnectWithConn", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
if err != nil {
t.Fatal(err)
}
defer ss.Close()
c, err := net.Dial(ss.Addr().Network(), ss.Addr().String())
if err != nil {
t.Fatal(err)
}
defer c.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
d.AuthMethods = []socks.AuthMethod{
socks.AuthMethodNotRequired,
socks.AuthMethodUsernamePassword,
}
d.Authenticate = (&socks.UsernamePassword{
Username: "username",
Password: "password",
}).Authenticate
a, err := d.DialWithConn(context.Background(), c, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err != nil {
t.Fatal(err)
}
if _, ok := a.(*socks.Addr); !ok {
t.Fatalf("got %+v; want socks.Addr", a)
}
})
t.Run("Cancel", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
@ -63,7 +79,7 @@ func TestDial(t *testing.T) {
defer cancel()
dialErr := make(chan error)
go func() {
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), net.JoinHostPort(targetHostname, targetPort))
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
c.Close()
}
@ -73,41 +89,37 @@ func TestDial(t *testing.T) {
cancel()
err = <-dialErr
if perr, nerr := parseDialError(err); perr != context.Canceled && nerr == nil {
t.Errorf("got %v; want context.Canceled or equivalent", err)
return
t.Fatalf("got %v; want context.Canceled or equivalent", err)
}
})
t.Run("Deadline", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
defer cancel()
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), net.JoinHostPort(targetHostname, targetPort))
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
c.Close()
}
if perr, nerr := parseDialError(err); perr != context.DeadlineExceeded && nerr == nil {
t.Errorf("got %v; want context.DeadlineExceeded or equivalent", err)
return
t.Fatalf("got %v; want context.DeadlineExceeded or equivalent", err)
}
})
t.Run("WithRogueServer", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, rogueCmdFunc)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
for i := 0; i < 2*len(rogueCmdList); i++ {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
defer cancel()
c, err := d.DialContext(ctx, targetNetwork, net.JoinHostPort(targetHostIP, targetPort))
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
t.Log(c.(*socks.Conn).BoundAddr())
c.Close()

View file

@ -75,7 +75,7 @@ const (
AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authetication methods
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
StatusSucceeded Reply = 0x00
)
@ -149,20 +149,13 @@ type Dialer struct {
// See func Dial of the net package of standard library for a
// description of the network and address parameters.
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
switch network {
case "tcp", "tcp6", "tcp4":
default:
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("network not implemented")}
}
switch d.cmd {
case CmdConnect, cmdBind:
default:
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("command not implemented")}
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
ctx = context.Background()
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
var err error
var c net.Conn
@ -185,11 +178,69 @@ func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.
return &Conn{Conn: c, boundAddr: a}, nil
}
// DialWithConn initiates a connection from SOCKS server to the target
// network and address using the connection c that is already
// connected to the SOCKS server.
//
// It returns the connection's local address assigned by the SOCKS
// server.
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
a, err := d.connect(ctx, c, address)
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return a, nil
}
// Dial connects to the provided address on the provided network.
//
// Deprecated: Use DialContext instead.
// Unlike DialContext, it returns a raw transport connection instead
// of a forward proxy connection.
//
// Deprecated: Use DialContext or DialWithConn instead.
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(context.Background(), network, address)
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
} else {
c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
return nil, err
}
return c, nil
}
func (d *Dialer) validateTarget(network, address string) error {
switch network {
case "tcp", "tcp6", "tcp4":
default:
return errors.New("network not implemented")
}
switch d.cmd {
case CmdConnect, cmdBind:
default:
return errors.New("command not implemented")
}
return nil
}
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {

View file

@ -98,7 +98,7 @@ func (h *Header) Marshal() ([]byte, error) {
return b, nil
}
// Parse parses b as an IPv4 header and sotres the result in h.
// Parse parses b as an IPv4 header and stores the result in h.
func (h *Header) Parse(b []byte) error {
if h == nil || len(b) < HeaderLen {
return errHeaderTooShort

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@ package webdav
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"io"
"mime"
@ -376,10 +377,37 @@ func findContentLength(ctx context.Context, fs FileSystem, ls LockSystem, name s
}
func findLastModified(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
return fi.ModTime().Format(http.TimeFormat), nil
return fi.ModTime().UTC().Format(http.TimeFormat), nil
}
// ErrNotImplemented should be returned by optional interfaces if they
// want the original implementation to be used.
var ErrNotImplemented = errors.New("not implemented")
// ContentTyper is an optional interface for the os.FileInfo
// objects returned by the FileSystem.
//
// If this interface is defined then it will be used to read the
// content type from the object.
//
// If this interface is not defined the file will be opened and the
// content type will be guessed from the initial contents of the file.
type ContentTyper interface {
// ContentType returns the content type for the file.
//
// If this returns error ErrNotImplemented then the error will
// be ignored and the base implementation will be used
// instead.
ContentType(ctx context.Context) (string, error)
}
func findContentType(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
if do, ok := fi.(ContentTyper); ok {
ctype, err := do.ContentType(ctx)
if err != ErrNotImplemented {
return ctype, err
}
}
f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0)
if err != nil {
return "", err
@ -402,7 +430,31 @@ func findContentType(ctx context.Context, fs FileSystem, ls LockSystem, name str
return ctype, err
}
// ETager is an optional interface for the os.FileInfo objects
// returned by the FileSystem.
//
// If this interface is defined then it will be used to read the ETag
// for the object.
//
// If this interface is not defined an ETag will be computed using the
// ModTime() and the Size() methods of the os.FileInfo object.
type ETager interface {
// ETag returns an ETag for the file. This should be of the
// form "value" or W/"value"
//
// If this returns error ErrNotImplemented then the error will
// be ignored and the base implementation will be used
// instead.
ETag(ctx context.Context) (string, error)
}
func findETag(ctx context.Context, fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) {
if do, ok := fi.(ETager); ok {
etag, err := do.ETag(ctx)
if err != ErrNotImplemented {
return etag, err
}
}
// The Apache http 2.4 web server by default concatenates the
// modification time and size of a file. We replicate the heuristic
// with nanosecond granularity.

View file

@ -10,6 +10,7 @@ import (
"net/http"
"os"
"reflect"
"regexp"
"sort"
"testing"
@ -29,7 +30,7 @@ func TestMemPS(t *testing.T) {
for i, p := range pst.Props {
switch p.XMLName {
case xml.Name{Space: "DAV:", Local: "getlastmodified"}:
p.InnerXML = []byte(fi.ModTime().Format(http.TimeFormat))
p.InnerXML = []byte(fi.ModTime().UTC().Format(http.TimeFormat))
pst.Props[i] = p
case xml.Name{Space: "DAV:", Local: "getetag"}:
if fi.IsDir() {
@ -611,3 +612,106 @@ func (f noDeadPropsFile) Readdir(count int) ([]os.FileInfo, error) { return f.f
func (f noDeadPropsFile) Seek(off int64, whence int) (int64, error) { return f.f.Seek(off, whence) }
func (f noDeadPropsFile) Stat() (os.FileInfo, error) { return f.f.Stat() }
func (f noDeadPropsFile) Write(p []byte) (int, error) { return f.f.Write(p) }
type overrideContentType struct {
os.FileInfo
contentType string
err error
}
func (o *overrideContentType) ContentType(ctx context.Context) (string, error) {
return o.contentType, o.err
}
func TestFindContentTypeOverride(t *testing.T) {
fs, err := buildTestFS([]string{"touch /file"})
if err != nil {
t.Fatalf("cannot create test filesystem: %v", err)
}
ctx := context.Background()
fi, err := fs.Stat(ctx, "/file")
if err != nil {
t.Fatalf("cannot Stat /file: %v", err)
}
// Check non overridden case
originalContentType, err := findContentType(ctx, fs, nil, "/file", fi)
if err != nil {
t.Fatalf("findContentType /file failed: %v", err)
}
if originalContentType != "text/plain; charset=utf-8" {
t.Fatalf("ContentType wrong want %q got %q", "text/plain; charset=utf-8", originalContentType)
}
// Now try overriding the ContentType
o := &overrideContentType{fi, "OverriddenContentType", nil}
ContentType, err := findContentType(ctx, fs, nil, "/file", o)
if err != nil {
t.Fatalf("findContentType /file failed: %v", err)
}
if ContentType != o.contentType {
t.Fatalf("ContentType wrong want %q got %q", o.contentType, ContentType)
}
// Now return ErrNotImplemented and check we get the original content type
o = &overrideContentType{fi, "OverriddenContentType", ErrNotImplemented}
ContentType, err = findContentType(ctx, fs, nil, "/file", o)
if err != nil {
t.Fatalf("findContentType /file failed: %v", err)
}
if ContentType != originalContentType {
t.Fatalf("ContentType wrong want %q got %q", originalContentType, ContentType)
}
}
type overrideETag struct {
os.FileInfo
eTag string
err error
}
func (o *overrideETag) ETag(ctx context.Context) (string, error) {
return o.eTag, o.err
}
func TestFindETagOverride(t *testing.T) {
fs, err := buildTestFS([]string{"touch /file"})
if err != nil {
t.Fatalf("cannot create test filesystem: %v", err)
}
ctx := context.Background()
fi, err := fs.Stat(ctx, "/file")
if err != nil {
t.Fatalf("cannot Stat /file: %v", err)
}
// Check non overridden case
originalETag, err := findETag(ctx, fs, nil, "/file", fi)
if err != nil {
t.Fatalf("findETag /file failed: %v", err)
}
matchETag := regexp.MustCompile(`^"-?[0-9a-f]{6,}"$`)
if !matchETag.MatchString(originalETag) {
t.Fatalf("ETag wrong, wanted something matching %v got %q", matchETag, originalETag)
}
// Now try overriding the ETag
o := &overrideETag{fi, `"OverriddenETag"`, nil}
ETag, err := findETag(ctx, fs, nil, "/file", o)
if err != nil {
t.Fatalf("findETag /file failed: %v", err)
}
if ETag != o.eTag {
t.Fatalf("ETag wrong want %q got %q", o.eTag, ETag)
}
// Now return ErrNotImplemented and check we get the original Etag
o = &overrideETag{fi, `"OverriddenETag"`, ErrNotImplemented}
ETag, err = findETag(ctx, fs, nil, "/file", o)
if err != nil {
t.Fatalf("findETag /file failed: %v", err)
}
if ETag != originalETag {
t.Fatalf("ETag wrong want %q got %q", originalETag, ETag)
}
}

16
vendor/golang.org/x/oauth2/cern/cern.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 cern provides constants for using OAuth2 to access CERN services.
package cern // import "golang.org/x/oauth2/cern"
import (
"golang.org/x/oauth2"
)
// Endpoint is CERN's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://oauth.web.cern.ch/OAuth/Authorize",
TokenURL: "https://oauth.web.cern.ch/OAuth/Token",
}

16
vendor/golang.org/x/oauth2/gitlab/gitlab.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 gitlab provides constants for using OAuth2 to access GitLab.
package gitlab // import "golang.org/x/oauth2/gitlab"
import (
"golang.org/x/oauth2"
)
// Endpoint is GitLab's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://gitlab.com/oauth/authorize",
TokenURL: "https://gitlab.com/oauth/token",
}

16
vendor/golang.org/x/oauth2/kakao/kakao.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 kakao provides constants for using OAuth2 to access Kakao.
package kakao // import "golang.org/x/oauth2/kakao"
import (
"golang.org/x/oauth2"
)
// Endpoint is Kakao's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://kauth.kakao.com/oauth/authorize",
TokenURL: "https://kauth.kakao.com/oauth/token",
}

View file

@ -11,6 +11,6 @@ import (
// Endpoint is LinkedIn's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{
AuthURL: "https://www.linkedin.com/uas/oauth2/authorization",
TokenURL: "https://www.linkedin.com/uas/oauth2/accessToken",
AuthURL: "https://www.linkedin.com/oauth/v2/authorization",
TokenURL: "https://www.linkedin.com/oauth/v2/accessToken",
}

View file

@ -3,7 +3,8 @@
// license that can be found in the LICENSE file.
// Package oauth2 provides support for making
// OAuth2 authorized and authenticated HTTP requests.
// OAuth2 authorized and authenticated HTTP requests,
// as specified in RFC 6749.
// It can additionally grant authorization with Bearer JWT.
package oauth2 // import "golang.org/x/oauth2"

View file

@ -31,9 +31,17 @@ type Transport struct {
}
// RoundTrip authorizes and authenticates the request with an
// access token. If no token exists or token is expired,
// tries to refresh/fetch a new token.
// access token from Transport's Source.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
reqBodyClosed := false
if req.Body != nil {
defer func() {
if !reqBodyClosed {
req.Body.Close()
}
}()
}
if t.Source == nil {
return nil, errors.New("oauth2: Transport's Source is nil")
}
@ -46,6 +54,10 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
token.SetAuthHeader(req2)
t.setModReq(req, req2)
res, err := t.base().RoundTrip(req2)
// req.Body is assumed to have been closed by the base RoundTripper.
reqBodyClosed = true
if err != nil {
t.setModReq(req, nil)
return nil, err

View file

@ -1,6 +1,8 @@
package oauth2
import (
"errors"
"io"
"net/http"
"net/http/httptest"
"testing"
@ -27,6 +29,64 @@ func TestTransportNilTokenSource(t *testing.T) {
}
}
type readCloseCounter struct {
CloseCount int
ReadErr error
}
func (r *readCloseCounter) Read(b []byte) (int, error) {
return 0, r.ReadErr
}
func (r *readCloseCounter) Close() error {
r.CloseCount++
return nil
}
func TestTransportCloseRequestBody(t *testing.T) {
tr := &Transport{}
server := newMockServer(func(w http.ResponseWriter, r *http.Request) {})
defer server.Close()
client := &http.Client{Transport: tr}
body := &readCloseCounter{
ReadErr: errors.New("readCloseCounter.Read not implemented"),
}
resp, err := client.Post(server.URL, "application/json", body)
if err == nil {
t.Errorf("got no errors, want an error with nil token source")
}
if resp != nil {
t.Errorf("Response = %v; want nil", resp)
}
if expected := 1; body.CloseCount != expected {
t.Errorf("Body was closed %d times, expected %d", body.CloseCount, expected)
}
}
func TestTransportCloseRequestBodySuccess(t *testing.T) {
tr := &Transport{
Source: StaticTokenSource(&Token{
AccessToken: "abc",
}),
}
server := newMockServer(func(w http.ResponseWriter, r *http.Request) {})
defer server.Close()
client := &http.Client{Transport: tr}
body := &readCloseCounter{
ReadErr: io.EOF,
}
resp, err := client.Post(server.URL, "application/json", body)
if err != nil {
t.Errorf("got error %v; expected none", err)
}
if resp == nil {
t.Errorf("Response is nil; expected non-nil")
}
if expected := 1; body.CloseCount != expected {
t.Errorf("Body was closed %d times, expected %d", body.CloseCount, expected)
}
}
func TestTransportTokenSource(t *testing.T) {
ts := &tokenSource{
token: &Token{

View file

@ -14,6 +14,6 @@ import (
// For more information see:
// https://dev.twitch.tv/docs/authentication
var Endpoint = oauth2.Endpoint{
AuthURL: "https://api.twitch.tv/kraken/oauth2/authorize",
TokenURL: "https://api.twitch.tv/kraken/oauth2/token",
AuthURL: "https://id.twitch.tv/oauth2/authorize",
TokenURL: "https://id.twitch.tv/oauth2/token",
}

7
vendor/golang.org/x/sys/cpu/cpu.go generated vendored
View file

@ -6,6 +6,9 @@
// various CPU architectures.
package cpu
// CacheLinePad is used to pad structs to avoid false sharing.
type CacheLinePad struct{ _ [cacheLineSize]byte }
// X86 contains the supported CPU features of the
// current X86/AMD64 platform. If the current platform
// is not X86/AMD64 then all feature flags are false.
@ -14,7 +17,7 @@ package cpu
// and HasAVX2 are only set if the OS supports XMM and YMM
// registers in addition to the CPUID feature bit being set.
var X86 struct {
_ [cacheLineSize]byte
_ CacheLinePad
HasAES bool // AES hardware implementation (AES NI)
HasADX bool // Multi-precision add-carry instruction extensions
HasAVX bool // Advanced vector extension
@ -31,5 +34,5 @@ var X86 struct {
HasSSSE3 bool // Supplemental streaming SIMD extension 3
HasSSE41 bool // Streaming SIMD extension 4 and 4.1
HasSSE42 bool // Streaming SIMD extension 4 and 4.2
_ [cacheLineSize]byte
_ CacheLinePad
}

16
vendor/golang.org/x/sys/cpu/cpu_gc_x86.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2018 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 386 amd64 amd64p32
// +build !gccgo
package cpu
// cpuid is implemented in cpu_x86.s for gc compiler
// and in cpu_gccgo.c for gccgo.
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler
// and in cpu_gccgo.c for gccgo.
func xgetbv() (eax, edx uint32)

43
vendor/golang.org/x/sys/cpu/cpu_gccgo.c generated vendored Normal file
View file

@ -0,0 +1,43 @@
// Copyright 2018 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 386 amd64 amd64p32
// +build gccgo
#include <cpuid.h>
#include <stdint.h>
// Need to wrap __get_cpuid_count because it's declared as static.
int
gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
}
// xgetbv reads the contents of an XCR (Extended Control Register)
// specified in the ECX register into registers EDX:EAX.
// Currently, the only supported value for XCR is 0.
//
// TODO: Replace with a better alternative:
//
// #include <xsaveintrin.h>
//
// #pragma GCC target("xsave")
//
// void gccgoXgetbv(uint32_t *eax, uint32_t *edx) {
// unsigned long long x = _xgetbv(0);
// *eax = x & 0xffffffff;
// *edx = (x >> 32) & 0xffffffff;
// }
//
// Note that _xgetbv is defined starting with GCC 8.
void
gccgoXgetbv(uint32_t *eax, uint32_t *edx)
{
__asm(" xorl %%ecx, %%ecx\n"
" xgetbv"
: "=a"(*eax), "=d"(*edx));
}

26
vendor/golang.org/x/sys/cpu/cpu_gccgo.go generated vendored Normal file
View file

@ -0,0 +1,26 @@
// Copyright 2018 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 386 amd64 amd64p32
// +build gccgo
package cpu
//extern gccgoGetCpuidCount
func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
var a, b, c, d uint32
gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
return a, b, c, d
}
//extern gccgoXgetbv
func gccgoXgetbv(eax, edx *uint32)
func xgetbv() (eax, edx uint32) {
var a, d uint32
gccgoXgetbv(&a, &d)
return a, d
}

View file

@ -14,7 +14,7 @@ import (
func TestAMD64minimalFeatures(t *testing.T) {
if runtime.GOARCH == "amd64" {
if !cpu.X86.HasSSE2 {
t.Fatalf("HasSSE2 expected true, got false")
t.Fatal("HasSSE2 expected true, got false")
}
}
}
@ -22,7 +22,7 @@ func TestAMD64minimalFeatures(t *testing.T) {
func TestAVX2hasAVX(t *testing.T) {
if runtime.GOARCH == "amd64" {
if cpu.X86.HasAVX2 && !cpu.X86.HasAVX {
t.Fatalf("HasAVX expected true, got false")
t.Fatal("HasAVX expected true, got false")
}
}
}

View file

@ -8,12 +8,6 @@ package cpu
const cacheLineSize = 64
// cpuid is implemented in cpu_x86.s.
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
// xgetbv with ecx = 0 is implemented in cpu_x86.s.
func xgetbv() (eax, edx uint32)
func init() {
maxID, _, _, _ := cpuid(0, 0)

View file

@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build 386 amd64 amd64p32
// +build !gccgo
#include "textflag.h"

View file

@ -140,7 +140,7 @@ echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
sort >_signal.grep
echo '// mkerrors.sh' "$@"
echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
echo '// Code generated by the command above; DO NOT EDIT.'
echo
go tool cgo -godefs -- "$@" _const.go >_error.out
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep

View file

@ -308,7 +308,7 @@ if($errors) {
print <<EOF;
// $cmdline
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
package plan9

View file

@ -1,5 +1,5 @@
// mksyscall.pl -l32 -plan9 syscall_plan9.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
package plan9

View file

@ -1,5 +1,5 @@
// mksyscall.pl -l32 -plan9 syscall_plan9.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
package plan9

View file

@ -1,5 +1,5 @@
// mksyscall.pl -l32 -plan9 -tags plan9,arm syscall_plan9.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
// +build plan9,arm

View file

@ -13,17 +13,17 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-64
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-88
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-112
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-64
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

View file

@ -11,7 +11,6 @@ import (
"go/build"
"net"
"os"
"syscall"
"testing"
"golang.org/x/sys/unix"
@ -72,24 +71,10 @@ func TestSCMCredentials(t *testing.T) {
defer cli.Close()
var ucred unix.Ucred
ucred.Pid = int32(os.Getpid() - 1)
ucred.Pid = int32(os.Getpid())
ucred.Uid = uint32(os.Getuid())
ucred.Gid = uint32(os.Getgid())
oob := unix.UnixCredentials(&ucred)
_, _, err = cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
if op, ok := err.(*net.OpError); ok {
err = op.Err
}
if sys, ok := err.(*os.SyscallError); ok {
err = sys.Err
}
if err != syscall.EPERM {
t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
}
// Fix the PID.
ucred.Pid = int32(os.Getpid())
oob = unix.UnixCredentials(&ucred)
// On SOCK_STREAM, this is internally going to send a dummy byte
n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)

View file

@ -1,51 +0,0 @@
// Copyright 2017 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.7
package unix_test
import (
"fmt"
"testing"
"golang.org/x/sys/unix"
)
func TestDevices(t *testing.T) {
testCases := []struct {
path string
major uint32
minor uint32
}{
// Most of the device major/minor numbers on Darwin are
// dynamically generated by devfs. These are some well-known
// static numbers.
{"/dev/ttyp0", 4, 0},
{"/dev/ttys0", 4, 48},
{"/dev/ptyp0", 5, 0},
{"/dev/ptyr0", 5, 32},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s %v:%v", tc.path, tc.major, tc.minor), func(t *testing.T) {
var stat unix.Stat_t
err := unix.Stat(tc.path, &stat)
if err != nil {
t.Errorf("failed to stat device: %v", err)
return
}
dev := uint64(stat.Rdev)
if unix.Major(dev) != tc.major {
t.Errorf("for %s Major(%#x) == %d, want %d", tc.path, dev, unix.Major(dev), tc.major)
}
if unix.Minor(dev) != tc.minor {
t.Errorf("for %s Minor(%#x) == %d, want %d", tc.path, dev, unix.Minor(dev), tc.minor)
}
if unix.Mkdev(tc.major, tc.minor) != dev {
t.Errorf("for %s Mkdev(%d, %d) == %#x, want %#x", tc.path, tc.major, tc.minor, unix.Mkdev(tc.major, tc.minor), dev)
}
})
}
}

View file

@ -1,50 +0,0 @@
// Copyright 2017 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.7
package unix_test
import (
"fmt"
"testing"
"golang.org/x/sys/unix"
)
func TestDevices(t *testing.T) {
testCases := []struct {
path string
major uint32
minor uint32
}{
// Minor is a cookie instead of an index on DragonFlyBSD
{"/dev/null", 10, 0x00000002},
{"/dev/random", 10, 0x00000003},
{"/dev/urandom", 10, 0x00000004},
{"/dev/zero", 10, 0x0000000c},
{"/dev/bpf", 15, 0xffff00ff},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s %v:%v", tc.path, tc.major, tc.minor), func(t *testing.T) {
var stat unix.Stat_t
err := unix.Stat(tc.path, &stat)
if err != nil {
t.Errorf("failed to stat device: %v", err)
return
}
dev := uint64(stat.Rdev)
if unix.Major(dev) != tc.major {
t.Errorf("for %s Major(%#x) == %d, want %d", tc.path, dev, unix.Major(dev), tc.major)
}
if unix.Minor(dev) != tc.minor {
t.Errorf("for %s Minor(%#x) == %d, want %d", tc.path, dev, unix.Minor(dev), tc.minor)
}
if unix.Mkdev(tc.major, tc.minor) != dev {
t.Errorf("for %s Mkdev(%d, %d) == %#x, want %#x", tc.path, tc.major, tc.minor, unix.Mkdev(tc.major, tc.minor), dev)
}
})
}
}

View file

@ -33,6 +33,9 @@ func TestDevices(t *testing.T) {
var stat unix.Stat_t
err := unix.Stat(tc.path, &stat)
if err != nil {
if err == unix.EACCES {
t.Skip("no permission to stat device, skipping test")
}
t.Errorf("failed to stat device: %v", err)
return
}

View file

@ -1,50 +0,0 @@
// Copyright 2017 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.7
package unix_test
import (
"fmt"
"testing"
"golang.org/x/sys/unix"
)
func TestDevices(t *testing.T) {
testCases := []struct {
path string
major uint32
minor uint32
}{
// well known major/minor numbers according to /dev/MAKEDEV on
// NetBSD 8.0
{"/dev/null", 2, 2},
{"/dev/zero", 2, 12},
{"/dev/random", 46, 0},
{"/dev/urandom", 46, 1},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s %v:%v", tc.path, tc.major, tc.minor), func(t *testing.T) {
var stat unix.Stat_t
err := unix.Stat(tc.path, &stat)
if err != nil {
t.Errorf("failed to stat device: %v", err)
return
}
dev := uint64(stat.Rdev)
if unix.Major(dev) != tc.major {
t.Errorf("for %s Major(%#x) == %d, want %d", tc.path, dev, unix.Major(dev), tc.major)
}
if unix.Minor(dev) != tc.minor {
t.Errorf("for %s Minor(%#x) == %d, want %d", tc.path, dev, unix.Minor(dev), tc.minor)
}
if unix.Mkdev(tc.major, tc.minor) != dev {
t.Errorf("for %s Mkdev(%d, %d) == %#x, want %#x", tc.path, tc.major, tc.minor, unix.Mkdev(tc.major, tc.minor), dev)
}
})
}
}

View file

@ -1,54 +0,0 @@
// Copyright 2017 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.7
package unix_test
import (
"fmt"
"testing"
"golang.org/x/sys/unix"
)
func TestDevices(t *testing.T) {
testCases := []struct {
path string
major uint32
minor uint32
}{
// well known major/minor numbers according to /dev/MAKEDEV on
// OpenBSD 6.0
{"/dev/null", 2, 2},
{"/dev/zero", 2, 12},
{"/dev/ttyp0", 5, 0},
{"/dev/ttyp1", 5, 1},
{"/dev/random", 45, 0},
{"/dev/srandom", 45, 1},
{"/dev/urandom", 45, 2},
{"/dev/arandom", 45, 3},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s %v:%v", tc.path, tc.major, tc.minor), func(t *testing.T) {
var stat unix.Stat_t
err := unix.Stat(tc.path, &stat)
if err != nil {
t.Errorf("failed to stat device: %v", err)
return
}
dev := uint64(stat.Rdev)
if unix.Major(dev) != tc.major {
t.Errorf("for %s Major(%#x) == %d, want %d", tc.path, dev, unix.Major(dev), tc.major)
}
if unix.Minor(dev) != tc.minor {
t.Errorf("for %s Minor(%#x) == %d, want %d", tc.path, dev, unix.Minor(dev), tc.minor)
}
if unix.Mkdev(tc.major, tc.minor) != dev {
t.Errorf("for %s Mkdev(%d, %d) == %#x, want %#x", tc.path, tc.major, tc.minor, unix.Mkdev(tc.major, tc.minor), dev)
}
})
}
}

View file

@ -1,51 +0,0 @@
// Copyright 2017 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.7
package unix_test
import (
"fmt"
"testing"
"golang.org/x/sys/unix"
)
func TestDevices(t *testing.T) {
testCases := []struct {
path string
major uint32
minor uint32
}{
// Well-known major/minor numbers on OpenSolaris according to
// /etc/name_to_major
{"/dev/zero", 134, 12},
{"/dev/null", 134, 2},
{"/dev/ptyp0", 172, 0},
{"/dev/ttyp0", 175, 0},
{"/dev/ttyp1", 175, 1},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s %v:%v", tc.path, tc.major, tc.minor), func(t *testing.T) {
var stat unix.Stat_t
err := unix.Stat(tc.path, &stat)
if err != nil {
t.Errorf("failed to stat device: %v", err)
return
}
dev := uint64(stat.Rdev)
if unix.Major(dev) != tc.major {
t.Errorf("for %s Major(%#x) == %d, want %d", tc.path, dev, unix.Major(dev), tc.major)
}
if unix.Minor(dev) != tc.minor {
t.Errorf("for %s Minor(%#x) == %d, want %d", tc.path, dev, unix.Minor(dev), tc.minor)
}
if unix.Mkdev(tc.major, tc.minor) != dev {
t.Errorf("for %s Mkdev(%d, %d) == %#x, want %#x", tc.path, tc.major, tc.minor, unix.Mkdev(tc.major, tc.minor), dev)
}
})
}
}

View file

@ -36,12 +36,3 @@ gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3
{
return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
// Define the use function in C so that it is not inlined.
extern void use(void *) __asm__ (GOSYM_PREFIX GOPKGPATH ".use") __attribute__((noinline));
void
use(void *p __attribute__ ((unused)))
{
}

View file

@ -1,4 +1,4 @@
FROM ubuntu:17.10
FROM ubuntu:18.04
# Dependencies to get the git sources and go binaries
RUN apt-get update && apt-get install -y --no-install-recommends \
@ -11,15 +11,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
# Get the git sources. If not cached, this takes O(5 minutes).
WORKDIR /git
RUN git config --global advice.detachedHead false
# Linux Kernel: Released 01 Apr 2018
RUN git clone --branch v4.16 --depth 1 https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
# Linux Kernel: Released 03 Jun 2018
RUN git clone --branch v4.17 --depth 1 https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
# GNU C library: Released 01 Feb 2018 (we should try to get a secure way to clone this)
RUN git clone --branch glibc-2.27 --depth 1 git://sourceware.org/git/glibc.git
# Get Go
ENV GOLANG_VERSION 1.10.1
ENV GOLANG_VERSION 1.10.3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 72d820dec546752e5a8303b33b009079c15c2390ce76d67cf514991646c6127b
ENV GOLANG_DOWNLOAD_SHA256 fa1b0e45d3b647c252f51f5e1204aba049cde4af177ef9f2181f43004f901035
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
&& echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - \

View file

@ -22,7 +22,6 @@ package unix
#include <dirent.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netpacket/packet.h>
#include <poll.h>
#include <sched.h>
#include <signal.h>
@ -38,6 +37,7 @@ package unix
#include <sys/select.h>
#include <sys/signal.h>
#include <sys/statfs.h>
#include <sys/statvfs.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/times.h>
@ -49,6 +49,9 @@ package unix
#include <linux/filter.h>
#include <linux/icmpv6.h>
#include <linux/keyctl.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter.h>
#include <linux/netlink.h>
#include <linux/perf_event.h>
#include <linux/rtnetlink.h>
@ -61,6 +64,7 @@ package unix
#include <utime.h>
#include <linux/can.h>
#include <linux/if_alg.h>
#include <linux/if_packet.h>
#include <linux/fs.h>
#include <linux/vm_sockets.h>
#include <linux/random.h>
@ -69,6 +73,7 @@ package unix
#include <linux/genetlink.h>
#include <linux/socket.h>
#include <linux/hdreg.h>
#include <linux/rtc.h>
// abi/abi.h generated by mkall.go.
#include "abi/abi.h"
@ -337,8 +342,6 @@ type _Gid_t C.gid_t
type Stat_t C.struct_stat
type Statfs_t C.struct_statfs
type StatxTimestamp C.struct_statx_timestamp
type Statx_t C.struct_statx
@ -972,3 +975,520 @@ type HDDriveCmdHdr C.struct_hd_drive_cmd_hdr
type HDGeometry C.struct_hd_geometry
type HDDriveID C.struct_hd_driveid
// Statfs
type Statfs_t C.struct_statfs
const (
ST_MANDLOCK = C.ST_MANDLOCK
ST_NOATIME = C.ST_NOATIME
ST_NODEV = C.ST_NODEV
ST_NODIRATIME = C.ST_NODIRATIME
ST_NOEXEC = C.ST_NOEXEC
ST_NOSUID = C.ST_NOSUID
ST_RDONLY = C.ST_RDONLY
ST_RELATIME = C.ST_RELATIME
ST_SYNCHRONOUS = C.ST_SYNCHRONOUS
)
// TPacket
type TpacketHdr C.struct_tpacket_hdr
type Tpacket2Hdr C.struct_tpacket2_hdr
type Tpacket3Hdr C.struct_tpacket3_hdr
type TpacketHdrVariant1 C.struct_tpacket_hdr_variant1
type TpacketBlockDesc C.struct_tpacket_block_desc
type TpacketReq C.struct_tpacket_req
type TpacketReq3 C.struct_tpacket_req3
type TpacketStats C.struct_tpacket_stats
type TpacketStatsV3 C.struct_tpacket_stats_v3
type TpacketAuxdata C.struct_tpacket_auxdata
const (
TPACKET_V1 = C.TPACKET_V1
TPACKET_V2 = C.TPACKET_V2
TPACKET_V3 = C.TPACKET_V3
)
const (
SizeofTpacketHdr = C.sizeof_struct_tpacket_hdr
SizeofTpacket2Hdr = C.sizeof_struct_tpacket2_hdr
SizeofTpacket3Hdr = C.sizeof_struct_tpacket3_hdr
)
// netfilter
// generated using:
// perl -nlE '/^\s*(NF\w+)/ && say "$1 = C.$1"' /usr/include/linux/netfilter.h
const (
NF_INET_PRE_ROUTING = C.NF_INET_PRE_ROUTING
NF_INET_LOCAL_IN = C.NF_INET_LOCAL_IN
NF_INET_FORWARD = C.NF_INET_FORWARD
NF_INET_LOCAL_OUT = C.NF_INET_LOCAL_OUT
NF_INET_POST_ROUTING = C.NF_INET_POST_ROUTING
NF_INET_NUMHOOKS = C.NF_INET_NUMHOOKS
)
const (
NF_NETDEV_INGRESS = C.NF_NETDEV_INGRESS
NF_NETDEV_NUMHOOKS = C.NF_NETDEV_NUMHOOKS
)
const (
NFPROTO_UNSPEC = C.NFPROTO_UNSPEC
NFPROTO_INET = C.NFPROTO_INET
NFPROTO_IPV4 = C.NFPROTO_IPV4
NFPROTO_ARP = C.NFPROTO_ARP
NFPROTO_NETDEV = C.NFPROTO_NETDEV
NFPROTO_BRIDGE = C.NFPROTO_BRIDGE
NFPROTO_IPV6 = C.NFPROTO_IPV6
NFPROTO_DECNET = C.NFPROTO_DECNET
NFPROTO_NUMPROTO = C.NFPROTO_NUMPROTO
)
// netfilter nfnetlink
type Nfgenmsg C.struct_nfgenmsg
const (
NFNL_BATCH_UNSPEC = C.NFNL_BATCH_UNSPEC
NFNL_BATCH_GENID = C.NFNL_BATCH_GENID
)
// netfilter nf_tables
// generated using:
// perl -nlE '/^\s*(NFT\w+)/ && say "$1 = C.$1"' /usr/include/linux/netfilter/nf_tables.h
const (
NFT_REG_VERDICT = C.NFT_REG_VERDICT
NFT_REG_1 = C.NFT_REG_1
NFT_REG_2 = C.NFT_REG_2
NFT_REG_3 = C.NFT_REG_3
NFT_REG_4 = C.NFT_REG_4
NFT_REG32_00 = C.NFT_REG32_00
NFT_REG32_01 = C.NFT_REG32_01
NFT_REG32_02 = C.NFT_REG32_02
NFT_REG32_03 = C.NFT_REG32_03
NFT_REG32_04 = C.NFT_REG32_04
NFT_REG32_05 = C.NFT_REG32_05
NFT_REG32_06 = C.NFT_REG32_06
NFT_REG32_07 = C.NFT_REG32_07
NFT_REG32_08 = C.NFT_REG32_08
NFT_REG32_09 = C.NFT_REG32_09
NFT_REG32_10 = C.NFT_REG32_10
NFT_REG32_11 = C.NFT_REG32_11
NFT_REG32_12 = C.NFT_REG32_12
NFT_REG32_13 = C.NFT_REG32_13
NFT_REG32_14 = C.NFT_REG32_14
NFT_REG32_15 = C.NFT_REG32_15
NFT_CONTINUE = C.NFT_CONTINUE
NFT_BREAK = C.NFT_BREAK
NFT_JUMP = C.NFT_JUMP
NFT_GOTO = C.NFT_GOTO
NFT_RETURN = C.NFT_RETURN
NFT_MSG_NEWTABLE = C.NFT_MSG_NEWTABLE
NFT_MSG_GETTABLE = C.NFT_MSG_GETTABLE
NFT_MSG_DELTABLE = C.NFT_MSG_DELTABLE
NFT_MSG_NEWCHAIN = C.NFT_MSG_NEWCHAIN
NFT_MSG_GETCHAIN = C.NFT_MSG_GETCHAIN
NFT_MSG_DELCHAIN = C.NFT_MSG_DELCHAIN
NFT_MSG_NEWRULE = C.NFT_MSG_NEWRULE
NFT_MSG_GETRULE = C.NFT_MSG_GETRULE
NFT_MSG_DELRULE = C.NFT_MSG_DELRULE
NFT_MSG_NEWSET = C.NFT_MSG_NEWSET
NFT_MSG_GETSET = C.NFT_MSG_GETSET
NFT_MSG_DELSET = C.NFT_MSG_DELSET
NFT_MSG_NEWSETELEM = C.NFT_MSG_NEWSETELEM
NFT_MSG_GETSETELEM = C.NFT_MSG_GETSETELEM
NFT_MSG_DELSETELEM = C.NFT_MSG_DELSETELEM
NFT_MSG_NEWGEN = C.NFT_MSG_NEWGEN
NFT_MSG_GETGEN = C.NFT_MSG_GETGEN
NFT_MSG_TRACE = C.NFT_MSG_TRACE
NFT_MSG_NEWOBJ = C.NFT_MSG_NEWOBJ
NFT_MSG_GETOBJ = C.NFT_MSG_GETOBJ
NFT_MSG_DELOBJ = C.NFT_MSG_DELOBJ
NFT_MSG_GETOBJ_RESET = C.NFT_MSG_GETOBJ_RESET
NFT_MSG_MAX = C.NFT_MSG_MAX
NFTA_LIST_UNPEC = C.NFTA_LIST_UNPEC
NFTA_LIST_ELEM = C.NFTA_LIST_ELEM
NFTA_HOOK_UNSPEC = C.NFTA_HOOK_UNSPEC
NFTA_HOOK_HOOKNUM = C.NFTA_HOOK_HOOKNUM
NFTA_HOOK_PRIORITY = C.NFTA_HOOK_PRIORITY
NFTA_HOOK_DEV = C.NFTA_HOOK_DEV
NFT_TABLE_F_DORMANT = C.NFT_TABLE_F_DORMANT
NFTA_TABLE_UNSPEC = C.NFTA_TABLE_UNSPEC
NFTA_TABLE_NAME = C.NFTA_TABLE_NAME
NFTA_TABLE_FLAGS = C.NFTA_TABLE_FLAGS
NFTA_TABLE_USE = C.NFTA_TABLE_USE
NFTA_CHAIN_UNSPEC = C.NFTA_CHAIN_UNSPEC
NFTA_CHAIN_TABLE = C.NFTA_CHAIN_TABLE
NFTA_CHAIN_HANDLE = C.NFTA_CHAIN_HANDLE
NFTA_CHAIN_NAME = C.NFTA_CHAIN_NAME
NFTA_CHAIN_HOOK = C.NFTA_CHAIN_HOOK
NFTA_CHAIN_POLICY = C.NFTA_CHAIN_POLICY
NFTA_CHAIN_USE = C.NFTA_CHAIN_USE
NFTA_CHAIN_TYPE = C.NFTA_CHAIN_TYPE
NFTA_CHAIN_COUNTERS = C.NFTA_CHAIN_COUNTERS
NFTA_CHAIN_PAD = C.NFTA_CHAIN_PAD
NFTA_RULE_UNSPEC = C.NFTA_RULE_UNSPEC
NFTA_RULE_TABLE = C.NFTA_RULE_TABLE
NFTA_RULE_CHAIN = C.NFTA_RULE_CHAIN
NFTA_RULE_HANDLE = C.NFTA_RULE_HANDLE
NFTA_RULE_EXPRESSIONS = C.NFTA_RULE_EXPRESSIONS
NFTA_RULE_COMPAT = C.NFTA_RULE_COMPAT
NFTA_RULE_POSITION = C.NFTA_RULE_POSITION
NFTA_RULE_USERDATA = C.NFTA_RULE_USERDATA
NFTA_RULE_PAD = C.NFTA_RULE_PAD
NFTA_RULE_ID = C.NFTA_RULE_ID
NFT_RULE_COMPAT_F_INV = C.NFT_RULE_COMPAT_F_INV
NFT_RULE_COMPAT_F_MASK = C.NFT_RULE_COMPAT_F_MASK
NFTA_RULE_COMPAT_UNSPEC = C.NFTA_RULE_COMPAT_UNSPEC
NFTA_RULE_COMPAT_PROTO = C.NFTA_RULE_COMPAT_PROTO
NFTA_RULE_COMPAT_FLAGS = C.NFTA_RULE_COMPAT_FLAGS
NFT_SET_ANONYMOUS = C.NFT_SET_ANONYMOUS
NFT_SET_CONSTANT = C.NFT_SET_CONSTANT
NFT_SET_INTERVAL = C.NFT_SET_INTERVAL
NFT_SET_MAP = C.NFT_SET_MAP
NFT_SET_TIMEOUT = C.NFT_SET_TIMEOUT
NFT_SET_EVAL = C.NFT_SET_EVAL
NFT_SET_OBJECT = C.NFT_SET_OBJECT
NFT_SET_POL_PERFORMANCE = C.NFT_SET_POL_PERFORMANCE
NFT_SET_POL_MEMORY = C.NFT_SET_POL_MEMORY
NFTA_SET_DESC_UNSPEC = C.NFTA_SET_DESC_UNSPEC
NFTA_SET_DESC_SIZE = C.NFTA_SET_DESC_SIZE
NFTA_SET_UNSPEC = C.NFTA_SET_UNSPEC
NFTA_SET_TABLE = C.NFTA_SET_TABLE
NFTA_SET_NAME = C.NFTA_SET_NAME
NFTA_SET_FLAGS = C.NFTA_SET_FLAGS
NFTA_SET_KEY_TYPE = C.NFTA_SET_KEY_TYPE
NFTA_SET_KEY_LEN = C.NFTA_SET_KEY_LEN
NFTA_SET_DATA_TYPE = C.NFTA_SET_DATA_TYPE
NFTA_SET_DATA_LEN = C.NFTA_SET_DATA_LEN
NFTA_SET_POLICY = C.NFTA_SET_POLICY
NFTA_SET_DESC = C.NFTA_SET_DESC
NFTA_SET_ID = C.NFTA_SET_ID
NFTA_SET_TIMEOUT = C.NFTA_SET_TIMEOUT
NFTA_SET_GC_INTERVAL = C.NFTA_SET_GC_INTERVAL
NFTA_SET_USERDATA = C.NFTA_SET_USERDATA
NFTA_SET_PAD = C.NFTA_SET_PAD
NFTA_SET_OBJ_TYPE = C.NFTA_SET_OBJ_TYPE
NFT_SET_ELEM_INTERVAL_END = C.NFT_SET_ELEM_INTERVAL_END
NFTA_SET_ELEM_UNSPEC = C.NFTA_SET_ELEM_UNSPEC
NFTA_SET_ELEM_KEY = C.NFTA_SET_ELEM_KEY
NFTA_SET_ELEM_DATA = C.NFTA_SET_ELEM_DATA
NFTA_SET_ELEM_FLAGS = C.NFTA_SET_ELEM_FLAGS
NFTA_SET_ELEM_TIMEOUT = C.NFTA_SET_ELEM_TIMEOUT
NFTA_SET_ELEM_EXPIRATION = C.NFTA_SET_ELEM_EXPIRATION
NFTA_SET_ELEM_USERDATA = C.NFTA_SET_ELEM_USERDATA
NFTA_SET_ELEM_EXPR = C.NFTA_SET_ELEM_EXPR
NFTA_SET_ELEM_PAD = C.NFTA_SET_ELEM_PAD
NFTA_SET_ELEM_OBJREF = C.NFTA_SET_ELEM_OBJREF
NFTA_SET_ELEM_LIST_UNSPEC = C.NFTA_SET_ELEM_LIST_UNSPEC
NFTA_SET_ELEM_LIST_TABLE = C.NFTA_SET_ELEM_LIST_TABLE
NFTA_SET_ELEM_LIST_SET = C.NFTA_SET_ELEM_LIST_SET
NFTA_SET_ELEM_LIST_ELEMENTS = C.NFTA_SET_ELEM_LIST_ELEMENTS
NFTA_SET_ELEM_LIST_SET_ID = C.NFTA_SET_ELEM_LIST_SET_ID
NFT_DATA_VALUE = C.NFT_DATA_VALUE
NFT_DATA_VERDICT = C.NFT_DATA_VERDICT
NFTA_DATA_UNSPEC = C.NFTA_DATA_UNSPEC
NFTA_DATA_VALUE = C.NFTA_DATA_VALUE
NFTA_DATA_VERDICT = C.NFTA_DATA_VERDICT
NFTA_VERDICT_UNSPEC = C.NFTA_VERDICT_UNSPEC
NFTA_VERDICT_CODE = C.NFTA_VERDICT_CODE
NFTA_VERDICT_CHAIN = C.NFTA_VERDICT_CHAIN
NFTA_EXPR_UNSPEC = C.NFTA_EXPR_UNSPEC
NFTA_EXPR_NAME = C.NFTA_EXPR_NAME
NFTA_EXPR_DATA = C.NFTA_EXPR_DATA
NFTA_IMMEDIATE_UNSPEC = C.NFTA_IMMEDIATE_UNSPEC
NFTA_IMMEDIATE_DREG = C.NFTA_IMMEDIATE_DREG
NFTA_IMMEDIATE_DATA = C.NFTA_IMMEDIATE_DATA
NFTA_BITWISE_UNSPEC = C.NFTA_BITWISE_UNSPEC
NFTA_BITWISE_SREG = C.NFTA_BITWISE_SREG
NFTA_BITWISE_DREG = C.NFTA_BITWISE_DREG
NFTA_BITWISE_LEN = C.NFTA_BITWISE_LEN
NFTA_BITWISE_MASK = C.NFTA_BITWISE_MASK
NFTA_BITWISE_XOR = C.NFTA_BITWISE_XOR
NFT_BYTEORDER_NTOH = C.NFT_BYTEORDER_NTOH
NFT_BYTEORDER_HTON = C.NFT_BYTEORDER_HTON
NFTA_BYTEORDER_UNSPEC = C.NFTA_BYTEORDER_UNSPEC
NFTA_BYTEORDER_SREG = C.NFTA_BYTEORDER_SREG
NFTA_BYTEORDER_DREG = C.NFTA_BYTEORDER_DREG
NFTA_BYTEORDER_OP = C.NFTA_BYTEORDER_OP
NFTA_BYTEORDER_LEN = C.NFTA_BYTEORDER_LEN
NFTA_BYTEORDER_SIZE = C.NFTA_BYTEORDER_SIZE
NFT_CMP_EQ = C.NFT_CMP_EQ
NFT_CMP_NEQ = C.NFT_CMP_NEQ
NFT_CMP_LT = C.NFT_CMP_LT
NFT_CMP_LTE = C.NFT_CMP_LTE
NFT_CMP_GT = C.NFT_CMP_GT
NFT_CMP_GTE = C.NFT_CMP_GTE
NFTA_CMP_UNSPEC = C.NFTA_CMP_UNSPEC
NFTA_CMP_SREG = C.NFTA_CMP_SREG
NFTA_CMP_OP = C.NFTA_CMP_OP
NFTA_CMP_DATA = C.NFTA_CMP_DATA
NFT_RANGE_EQ = C.NFT_RANGE_EQ
NFT_RANGE_NEQ = C.NFT_RANGE_NEQ
NFTA_RANGE_UNSPEC = C.NFTA_RANGE_UNSPEC
NFTA_RANGE_SREG = C.NFTA_RANGE_SREG
NFTA_RANGE_OP = C.NFTA_RANGE_OP
NFTA_RANGE_FROM_DATA = C.NFTA_RANGE_FROM_DATA
NFTA_RANGE_TO_DATA = C.NFTA_RANGE_TO_DATA
NFT_LOOKUP_F_INV = C.NFT_LOOKUP_F_INV
NFTA_LOOKUP_UNSPEC = C.NFTA_LOOKUP_UNSPEC
NFTA_LOOKUP_SET = C.NFTA_LOOKUP_SET
NFTA_LOOKUP_SREG = C.NFTA_LOOKUP_SREG
NFTA_LOOKUP_DREG = C.NFTA_LOOKUP_DREG
NFTA_LOOKUP_SET_ID = C.NFTA_LOOKUP_SET_ID
NFTA_LOOKUP_FLAGS = C.NFTA_LOOKUP_FLAGS
NFT_DYNSET_OP_ADD = C.NFT_DYNSET_OP_ADD
NFT_DYNSET_OP_UPDATE = C.NFT_DYNSET_OP_UPDATE
NFT_DYNSET_F_INV = C.NFT_DYNSET_F_INV
NFTA_DYNSET_UNSPEC = C.NFTA_DYNSET_UNSPEC
NFTA_DYNSET_SET_NAME = C.NFTA_DYNSET_SET_NAME
NFTA_DYNSET_SET_ID = C.NFTA_DYNSET_SET_ID
NFTA_DYNSET_OP = C.NFTA_DYNSET_OP
NFTA_DYNSET_SREG_KEY = C.NFTA_DYNSET_SREG_KEY
NFTA_DYNSET_SREG_DATA = C.NFTA_DYNSET_SREG_DATA
NFTA_DYNSET_TIMEOUT = C.NFTA_DYNSET_TIMEOUT
NFTA_DYNSET_EXPR = C.NFTA_DYNSET_EXPR
NFTA_DYNSET_PAD = C.NFTA_DYNSET_PAD
NFTA_DYNSET_FLAGS = C.NFTA_DYNSET_FLAGS
NFT_PAYLOAD_LL_HEADER = C.NFT_PAYLOAD_LL_HEADER
NFT_PAYLOAD_NETWORK_HEADER = C.NFT_PAYLOAD_NETWORK_HEADER
NFT_PAYLOAD_TRANSPORT_HEADER = C.NFT_PAYLOAD_TRANSPORT_HEADER
NFT_PAYLOAD_CSUM_NONE = C.NFT_PAYLOAD_CSUM_NONE
NFT_PAYLOAD_CSUM_INET = C.NFT_PAYLOAD_CSUM_INET
NFT_PAYLOAD_L4CSUM_PSEUDOHDR = C.NFT_PAYLOAD_L4CSUM_PSEUDOHDR
NFTA_PAYLOAD_UNSPEC = C.NFTA_PAYLOAD_UNSPEC
NFTA_PAYLOAD_DREG = C.NFTA_PAYLOAD_DREG
NFTA_PAYLOAD_BASE = C.NFTA_PAYLOAD_BASE
NFTA_PAYLOAD_OFFSET = C.NFTA_PAYLOAD_OFFSET
NFTA_PAYLOAD_LEN = C.NFTA_PAYLOAD_LEN
NFTA_PAYLOAD_SREG = C.NFTA_PAYLOAD_SREG
NFTA_PAYLOAD_CSUM_TYPE = C.NFTA_PAYLOAD_CSUM_TYPE
NFTA_PAYLOAD_CSUM_OFFSET = C.NFTA_PAYLOAD_CSUM_OFFSET
NFTA_PAYLOAD_CSUM_FLAGS = C.NFTA_PAYLOAD_CSUM_FLAGS
NFT_EXTHDR_F_PRESENT = C.NFT_EXTHDR_F_PRESENT
NFT_EXTHDR_OP_IPV6 = C.NFT_EXTHDR_OP_IPV6
NFT_EXTHDR_OP_TCPOPT = C.NFT_EXTHDR_OP_TCPOPT
NFTA_EXTHDR_UNSPEC = C.NFTA_EXTHDR_UNSPEC
NFTA_EXTHDR_DREG = C.NFTA_EXTHDR_DREG
NFTA_EXTHDR_TYPE = C.NFTA_EXTHDR_TYPE
NFTA_EXTHDR_OFFSET = C.NFTA_EXTHDR_OFFSET
NFTA_EXTHDR_LEN = C.NFTA_EXTHDR_LEN
NFTA_EXTHDR_FLAGS = C.NFTA_EXTHDR_FLAGS
NFTA_EXTHDR_OP = C.NFTA_EXTHDR_OP
NFTA_EXTHDR_SREG = C.NFTA_EXTHDR_SREG
NFT_META_LEN = C.NFT_META_LEN
NFT_META_PROTOCOL = C.NFT_META_PROTOCOL
NFT_META_PRIORITY = C.NFT_META_PRIORITY
NFT_META_MARK = C.NFT_META_MARK
NFT_META_IIF = C.NFT_META_IIF
NFT_META_OIF = C.NFT_META_OIF
NFT_META_IIFNAME = C.NFT_META_IIFNAME
NFT_META_OIFNAME = C.NFT_META_OIFNAME
NFT_META_IIFTYPE = C.NFT_META_IIFTYPE
NFT_META_OIFTYPE = C.NFT_META_OIFTYPE
NFT_META_SKUID = C.NFT_META_SKUID
NFT_META_SKGID = C.NFT_META_SKGID
NFT_META_NFTRACE = C.NFT_META_NFTRACE
NFT_META_RTCLASSID = C.NFT_META_RTCLASSID
NFT_META_SECMARK = C.NFT_META_SECMARK
NFT_META_NFPROTO = C.NFT_META_NFPROTO
NFT_META_L4PROTO = C.NFT_META_L4PROTO
NFT_META_BRI_IIFNAME = C.NFT_META_BRI_IIFNAME
NFT_META_BRI_OIFNAME = C.NFT_META_BRI_OIFNAME
NFT_META_PKTTYPE = C.NFT_META_PKTTYPE
NFT_META_CPU = C.NFT_META_CPU
NFT_META_IIFGROUP = C.NFT_META_IIFGROUP
NFT_META_OIFGROUP = C.NFT_META_OIFGROUP
NFT_META_CGROUP = C.NFT_META_CGROUP
NFT_META_PRANDOM = C.NFT_META_PRANDOM
NFT_RT_CLASSID = C.NFT_RT_CLASSID
NFT_RT_NEXTHOP4 = C.NFT_RT_NEXTHOP4
NFT_RT_NEXTHOP6 = C.NFT_RT_NEXTHOP6
NFT_RT_TCPMSS = C.NFT_RT_TCPMSS
NFT_HASH_JENKINS = C.NFT_HASH_JENKINS
NFT_HASH_SYM = C.NFT_HASH_SYM
NFTA_HASH_UNSPEC = C.NFTA_HASH_UNSPEC
NFTA_HASH_SREG = C.NFTA_HASH_SREG
NFTA_HASH_DREG = C.NFTA_HASH_DREG
NFTA_HASH_LEN = C.NFTA_HASH_LEN
NFTA_HASH_MODULUS = C.NFTA_HASH_MODULUS
NFTA_HASH_SEED = C.NFTA_HASH_SEED
NFTA_HASH_OFFSET = C.NFTA_HASH_OFFSET
NFTA_HASH_TYPE = C.NFTA_HASH_TYPE
NFTA_META_UNSPEC = C.NFTA_META_UNSPEC
NFTA_META_DREG = C.NFTA_META_DREG
NFTA_META_KEY = C.NFTA_META_KEY
NFTA_META_SREG = C.NFTA_META_SREG
NFTA_RT_UNSPEC = C.NFTA_RT_UNSPEC
NFTA_RT_DREG = C.NFTA_RT_DREG
NFTA_RT_KEY = C.NFTA_RT_KEY
NFT_CT_STATE = C.NFT_CT_STATE
NFT_CT_DIRECTION = C.NFT_CT_DIRECTION
NFT_CT_STATUS = C.NFT_CT_STATUS
NFT_CT_MARK = C.NFT_CT_MARK
NFT_CT_SECMARK = C.NFT_CT_SECMARK
NFT_CT_EXPIRATION = C.NFT_CT_EXPIRATION
NFT_CT_HELPER = C.NFT_CT_HELPER
NFT_CT_L3PROTOCOL = C.NFT_CT_L3PROTOCOL
NFT_CT_SRC = C.NFT_CT_SRC
NFT_CT_DST = C.NFT_CT_DST
NFT_CT_PROTOCOL = C.NFT_CT_PROTOCOL
NFT_CT_PROTO_SRC = C.NFT_CT_PROTO_SRC
NFT_CT_PROTO_DST = C.NFT_CT_PROTO_DST
NFT_CT_LABELS = C.NFT_CT_LABELS
NFT_CT_PKTS = C.NFT_CT_PKTS
NFT_CT_BYTES = C.NFT_CT_BYTES
NFT_CT_AVGPKT = C.NFT_CT_AVGPKT
NFT_CT_ZONE = C.NFT_CT_ZONE
NFT_CT_EVENTMASK = C.NFT_CT_EVENTMASK
NFTA_CT_UNSPEC = C.NFTA_CT_UNSPEC
NFTA_CT_DREG = C.NFTA_CT_DREG
NFTA_CT_KEY = C.NFTA_CT_KEY
NFTA_CT_DIRECTION = C.NFTA_CT_DIRECTION
NFTA_CT_SREG = C.NFTA_CT_SREG
NFT_LIMIT_PKTS = C.NFT_LIMIT_PKTS
NFT_LIMIT_PKT_BYTES = C.NFT_LIMIT_PKT_BYTES
NFT_LIMIT_F_INV = C.NFT_LIMIT_F_INV
NFTA_LIMIT_UNSPEC = C.NFTA_LIMIT_UNSPEC
NFTA_LIMIT_RATE = C.NFTA_LIMIT_RATE
NFTA_LIMIT_UNIT = C.NFTA_LIMIT_UNIT
NFTA_LIMIT_BURST = C.NFTA_LIMIT_BURST
NFTA_LIMIT_TYPE = C.NFTA_LIMIT_TYPE
NFTA_LIMIT_FLAGS = C.NFTA_LIMIT_FLAGS
NFTA_LIMIT_PAD = C.NFTA_LIMIT_PAD
NFTA_COUNTER_UNSPEC = C.NFTA_COUNTER_UNSPEC
NFTA_COUNTER_BYTES = C.NFTA_COUNTER_BYTES
NFTA_COUNTER_PACKETS = C.NFTA_COUNTER_PACKETS
NFTA_COUNTER_PAD = C.NFTA_COUNTER_PAD
NFTA_LOG_UNSPEC = C.NFTA_LOG_UNSPEC
NFTA_LOG_GROUP = C.NFTA_LOG_GROUP
NFTA_LOG_PREFIX = C.NFTA_LOG_PREFIX
NFTA_LOG_SNAPLEN = C.NFTA_LOG_SNAPLEN
NFTA_LOG_QTHRESHOLD = C.NFTA_LOG_QTHRESHOLD
NFTA_LOG_LEVEL = C.NFTA_LOG_LEVEL
NFTA_LOG_FLAGS = C.NFTA_LOG_FLAGS
NFTA_QUEUE_UNSPEC = C.NFTA_QUEUE_UNSPEC
NFTA_QUEUE_NUM = C.NFTA_QUEUE_NUM
NFTA_QUEUE_TOTAL = C.NFTA_QUEUE_TOTAL
NFTA_QUEUE_FLAGS = C.NFTA_QUEUE_FLAGS
NFTA_QUEUE_SREG_QNUM = C.NFTA_QUEUE_SREG_QNUM
NFT_QUOTA_F_INV = C.NFT_QUOTA_F_INV
NFT_QUOTA_F_DEPLETED = C.NFT_QUOTA_F_DEPLETED
NFTA_QUOTA_UNSPEC = C.NFTA_QUOTA_UNSPEC
NFTA_QUOTA_BYTES = C.NFTA_QUOTA_BYTES
NFTA_QUOTA_FLAGS = C.NFTA_QUOTA_FLAGS
NFTA_QUOTA_PAD = C.NFTA_QUOTA_PAD
NFTA_QUOTA_CONSUMED = C.NFTA_QUOTA_CONSUMED
NFT_REJECT_ICMP_UNREACH = C.NFT_REJECT_ICMP_UNREACH
NFT_REJECT_TCP_RST = C.NFT_REJECT_TCP_RST
NFT_REJECT_ICMPX_UNREACH = C.NFT_REJECT_ICMPX_UNREACH
NFT_REJECT_ICMPX_NO_ROUTE = C.NFT_REJECT_ICMPX_NO_ROUTE
NFT_REJECT_ICMPX_PORT_UNREACH = C.NFT_REJECT_ICMPX_PORT_UNREACH
NFT_REJECT_ICMPX_HOST_UNREACH = C.NFT_REJECT_ICMPX_HOST_UNREACH
NFT_REJECT_ICMPX_ADMIN_PROHIBITED = C.NFT_REJECT_ICMPX_ADMIN_PROHIBITED
NFTA_REJECT_UNSPEC = C.NFTA_REJECT_UNSPEC
NFTA_REJECT_TYPE = C.NFTA_REJECT_TYPE
NFTA_REJECT_ICMP_CODE = C.NFTA_REJECT_ICMP_CODE
NFT_NAT_SNAT = C.NFT_NAT_SNAT
NFT_NAT_DNAT = C.NFT_NAT_DNAT
NFTA_NAT_UNSPEC = C.NFTA_NAT_UNSPEC
NFTA_NAT_TYPE = C.NFTA_NAT_TYPE
NFTA_NAT_FAMILY = C.NFTA_NAT_FAMILY
NFTA_NAT_REG_ADDR_MIN = C.NFTA_NAT_REG_ADDR_MIN
NFTA_NAT_REG_ADDR_MAX = C.NFTA_NAT_REG_ADDR_MAX
NFTA_NAT_REG_PROTO_MIN = C.NFTA_NAT_REG_PROTO_MIN
NFTA_NAT_REG_PROTO_MAX = C.NFTA_NAT_REG_PROTO_MAX
NFTA_NAT_FLAGS = C.NFTA_NAT_FLAGS
NFTA_MASQ_UNSPEC = C.NFTA_MASQ_UNSPEC
NFTA_MASQ_FLAGS = C.NFTA_MASQ_FLAGS
NFTA_MASQ_REG_PROTO_MIN = C.NFTA_MASQ_REG_PROTO_MIN
NFTA_MASQ_REG_PROTO_MAX = C.NFTA_MASQ_REG_PROTO_MAX
NFTA_REDIR_UNSPEC = C.NFTA_REDIR_UNSPEC
NFTA_REDIR_REG_PROTO_MIN = C.NFTA_REDIR_REG_PROTO_MIN
NFTA_REDIR_REG_PROTO_MAX = C.NFTA_REDIR_REG_PROTO_MAX
NFTA_REDIR_FLAGS = C.NFTA_REDIR_FLAGS
NFTA_DUP_UNSPEC = C.NFTA_DUP_UNSPEC
NFTA_DUP_SREG_ADDR = C.NFTA_DUP_SREG_ADDR
NFTA_DUP_SREG_DEV = C.NFTA_DUP_SREG_DEV
NFTA_FWD_UNSPEC = C.NFTA_FWD_UNSPEC
NFTA_FWD_SREG_DEV = C.NFTA_FWD_SREG_DEV
NFTA_OBJREF_UNSPEC = C.NFTA_OBJREF_UNSPEC
NFTA_OBJREF_IMM_TYPE = C.NFTA_OBJREF_IMM_TYPE
NFTA_OBJREF_IMM_NAME = C.NFTA_OBJREF_IMM_NAME
NFTA_OBJREF_SET_SREG = C.NFTA_OBJREF_SET_SREG
NFTA_OBJREF_SET_NAME = C.NFTA_OBJREF_SET_NAME
NFTA_OBJREF_SET_ID = C.NFTA_OBJREF_SET_ID
NFTA_GEN_UNSPEC = C.NFTA_GEN_UNSPEC
NFTA_GEN_ID = C.NFTA_GEN_ID
NFTA_GEN_PROC_PID = C.NFTA_GEN_PROC_PID
NFTA_GEN_PROC_NAME = C.NFTA_GEN_PROC_NAME
NFTA_FIB_UNSPEC = C.NFTA_FIB_UNSPEC
NFTA_FIB_DREG = C.NFTA_FIB_DREG
NFTA_FIB_RESULT = C.NFTA_FIB_RESULT
NFTA_FIB_FLAGS = C.NFTA_FIB_FLAGS
NFT_FIB_RESULT_UNSPEC = C.NFT_FIB_RESULT_UNSPEC
NFT_FIB_RESULT_OIF = C.NFT_FIB_RESULT_OIF
NFT_FIB_RESULT_OIFNAME = C.NFT_FIB_RESULT_OIFNAME
NFT_FIB_RESULT_ADDRTYPE = C.NFT_FIB_RESULT_ADDRTYPE
NFTA_FIB_F_SADDR = C.NFTA_FIB_F_SADDR
NFTA_FIB_F_DADDR = C.NFTA_FIB_F_DADDR
NFTA_FIB_F_MARK = C.NFTA_FIB_F_MARK
NFTA_FIB_F_IIF = C.NFTA_FIB_F_IIF
NFTA_FIB_F_OIF = C.NFTA_FIB_F_OIF
NFTA_FIB_F_PRESENT = C.NFTA_FIB_F_PRESENT
NFTA_CT_HELPER_UNSPEC = C.NFTA_CT_HELPER_UNSPEC
NFTA_CT_HELPER_NAME = C.NFTA_CT_HELPER_NAME
NFTA_CT_HELPER_L3PROTO = C.NFTA_CT_HELPER_L3PROTO
NFTA_CT_HELPER_L4PROTO = C.NFTA_CT_HELPER_L4PROTO
NFTA_OBJ_UNSPEC = C.NFTA_OBJ_UNSPEC
NFTA_OBJ_TABLE = C.NFTA_OBJ_TABLE
NFTA_OBJ_NAME = C.NFTA_OBJ_NAME
NFTA_OBJ_TYPE = C.NFTA_OBJ_TYPE
NFTA_OBJ_DATA = C.NFTA_OBJ_DATA
NFTA_OBJ_USE = C.NFTA_OBJ_USE
NFTA_TRACE_UNSPEC = C.NFTA_TRACE_UNSPEC
NFTA_TRACE_TABLE = C.NFTA_TRACE_TABLE
NFTA_TRACE_CHAIN = C.NFTA_TRACE_CHAIN
NFTA_TRACE_RULE_HANDLE = C.NFTA_TRACE_RULE_HANDLE
NFTA_TRACE_TYPE = C.NFTA_TRACE_TYPE
NFTA_TRACE_VERDICT = C.NFTA_TRACE_VERDICT
NFTA_TRACE_ID = C.NFTA_TRACE_ID
NFTA_TRACE_LL_HEADER = C.NFTA_TRACE_LL_HEADER
NFTA_TRACE_NETWORK_HEADER = C.NFTA_TRACE_NETWORK_HEADER
NFTA_TRACE_TRANSPORT_HEADER = C.NFTA_TRACE_TRANSPORT_HEADER
NFTA_TRACE_IIF = C.NFTA_TRACE_IIF
NFTA_TRACE_IIFTYPE = C.NFTA_TRACE_IIFTYPE
NFTA_TRACE_OIF = C.NFTA_TRACE_OIF
NFTA_TRACE_OIFTYPE = C.NFTA_TRACE_OIFTYPE
NFTA_TRACE_MARK = C.NFTA_TRACE_MARK
NFTA_TRACE_NFPROTO = C.NFTA_TRACE_NFPROTO
NFTA_TRACE_POLICY = C.NFTA_TRACE_POLICY
NFTA_TRACE_PAD = C.NFTA_TRACE_PAD
NFT_TRACETYPE_UNSPEC = C.NFT_TRACETYPE_UNSPEC
NFT_TRACETYPE_POLICY = C.NFT_TRACETYPE_POLICY
NFT_TRACETYPE_RETURN = C.NFT_TRACETYPE_RETURN
NFT_TRACETYPE_RULE = C.NFT_TRACETYPE_RULE
NFTA_NG_UNSPEC = C.NFTA_NG_UNSPEC
NFTA_NG_DREG = C.NFTA_NG_DREG
NFTA_NG_MODULUS = C.NFTA_NG_MODULUS
NFTA_NG_TYPE = C.NFTA_NG_TYPE
NFTA_NG_OFFSET = C.NFTA_NG_OFFSET
NFT_NG_INCREMENTAL = C.NFT_NG_INCREMENTAL
NFT_NG_RANDOM = C.NFT_NG_RANDOM
)
type RTCTime C.struct_rtc_time
type RTCWkAlrm C.struct_rtc_wkalrm
type RTCPLLInfo C.struct_rtc_pll_info

View file

@ -50,6 +50,7 @@ includes_Darwin='
#include <sys/mount.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <sys/xattr.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
@ -171,6 +172,8 @@ struct ltchars {
#include <linux/filter.h>
#include <linux/fs.h>
#include <linux/keyctl.h>
#include <linux/magic.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <linux/perf_event.h>
#include <linux/random.h>
@ -190,6 +193,7 @@ struct ltchars {
#include <linux/stat.h>
#include <linux/watchdog.h>
#include <linux/hdreg.h>
#include <linux/rtc.h>
#include <net/route.h>
#include <asm/termbits.h>
@ -384,7 +388,8 @@ ccflags="$@"
$2 ~ /^TC[IO](ON|OFF)$/ ||
$2 ~ /^IN_/ ||
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|T?PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
$2 ~ /^TP_STATUS_/ ||
$2 ~ /^FALLOC_/ ||
$2 == "ICMPV6_FILTER" ||
$2 == "SOMAXCONN" ||
@ -400,7 +405,7 @@ ccflags="$@"
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
$2 !~ "NLA_TYPE_MASK" &&
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
$2 ~ /^TCGET/ ||
@ -426,6 +431,8 @@ ccflags="$@"
$2 ~ /^PERF_EVENT_IOC_/ ||
$2 ~ /^SECCOMP_MODE_/ ||
$2 ~ /^SPLICE_/ ||
$2 !~ /^AUDIT_RECORD_MAGIC/ &&
$2 ~ /^[A-Z0-9_]+_MAGIC2?$/ ||
$2 ~ /^(VM|VMADDR)_/ ||
$2 ~ /^IOCTL_VM_SOCKETS_/ ||
$2 ~ /^(TASKSTATS|TS)_/ ||
@ -433,10 +440,11 @@ ccflags="$@"
$2 ~ /^GENL_/ ||
$2 ~ /^STATX_/ ||
$2 ~ /^UTIME_/ ||
$2 ~ /^XATTR_(CREATE|REPLACE)/ ||
$2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ ||
$2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ ||
$2 ~ /^FSOPT_/ ||
$2 ~ /^WDIOC_/ ||
$2 ~ /^NFN/ ||
$2 ~ /^(HDIO|WIN|SMART)_/ ||
$2 !~ "WMESGLEN" &&
$2 ~ /^W[A-Z0-9]+$/ ||

View file

@ -74,7 +74,7 @@ func main() {
b = removePaddingFieldsRegex.ReplaceAll(b, []byte("_"))
// Remove padding, hidden, or unused fields
removeFieldsRegex = regexp.MustCompile(`\bX_\S+`)
removeFieldsRegex = regexp.MustCompile(`\b(X_\S+|Padding)`)
b = removeFieldsRegex.ReplaceAll(b, []byte("_"))
// Remove the first line of warning from cgo

View file

@ -240,7 +240,7 @@ foreach my $header (@headers) {
print <<EOF;
// mksysctl_openbsd.pl
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
// +build $ENV{'GOARCH'},$ENV{'GOOS'}

View file

@ -13,7 +13,7 @@ import (
)
const (
SYS_PLEDGE = 108
_SYS_PLEDGE = 108
)
// Pledge implements the pledge syscall. For more information see pledge(2).
@ -30,7 +30,7 @@ func Pledge(promises string, paths []string) error {
}
pathsUnsafe = unsafe.Pointer(&pathsPtr[0])
}
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(promisesUnsafe), uintptr(pathsUnsafe), 0)
_, _, e := syscall.Syscall(_SYS_PLEDGE, uintptr(promisesUnsafe), uintptr(pathsUnsafe), 0)
if e != 0 {
return e
}

View file

@ -176,6 +176,88 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return
}
func xattrPointer(dest []byte) *byte {
// It's only when dest is set to NULL that the OS X implementations of
// getxattr() and listxattr() return the current sizes of the named attributes.
// An empty byte array is not sufficient. To maintain the same behaviour as the
// linux implementation, we wrap around the system calls and pass in NULL when
// dest is empty.
var destp *byte
if len(dest) > 0 {
destp = &dest[0]
}
return destp
}
//sys getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error)
func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
return getxattr(path, attr, xattrPointer(dest), len(dest), 0, 0)
}
func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
return getxattr(link, attr, xattrPointer(dest), len(dest), 0, XATTR_NOFOLLOW)
}
//sys setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error)
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
// The parameters for the OS X implementation vary slightly compared to the
// linux system call, specifically the position parameter:
//
// linux:
// int setxattr(
// const char *path,
// const char *name,
// const void *value,
// size_t size,
// int flags
// );
//
// darwin:
// int setxattr(
// const char *path,
// const char *name,
// void *value,
// size_t size,
// u_int32_t position,
// int options
// );
//
// position specifies the offset within the extended attribute. In the
// current implementation, only the resource fork extended attribute makes
// use of this argument. For all others, position is reserved. We simply
// default to setting it to zero.
return setxattr(path, attr, xattrPointer(data), len(data), 0, flags)
}
func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
return setxattr(link, attr, xattrPointer(data), len(data), 0, flags|XATTR_NOFOLLOW)
}
//sys removexattr(path string, attr string, options int) (err error)
func Removexattr(path string, attr string) (err error) {
// We wrap around and explicitly zero out the options provided to the OS X
// implementation of removexattr, we do so for interoperability with the
// linux variant.
return removexattr(path, attr, 0)
}
func Lremovexattr(link string, attr string) (err error) {
return removexattr(link, attr, XATTR_NOFOLLOW)
}
//sys listxattr(path string, dest *byte, size int, options int) (sz int, err error)
func Listxattr(path string, dest []byte) (sz int, err error) {
return listxattr(path, xattrPointer(dest), len(dest), 0)
}
func Llistxattr(link string, dest []byte) (sz int, err error) {
return listxattr(link, xattrPointer(dest), len(dest), XATTR_NOFOLLOW)
}
func setattrlistTimes(path string, times []Timespec, flags int) error {
_p0, err := BytePtrFromString(path)
if err != nil {
@ -447,13 +529,9 @@ func Uname(uname *Utsname) error {
// Watchevent
// Waitevent
// Modwatch
// Getxattr
// Fgetxattr
// Setxattr
// Fsetxattr
// Removexattr
// Fremovexattr
// Listxattr
// Flistxattr
// Fsctl
// Initgroups

19
vendor/golang.org/x/sys/unix/syscall_darwin_test.go generated vendored Normal file
View file

@ -0,0 +1,19 @@
// Copyright 2018 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 unix_test
// stringsFromByteSlice converts a sequence of attributes to a []string.
// On Darwin, each entry is a NULL-terminated string.
func stringsFromByteSlice(buf []byte) []string {
var result []string
off := 0
for i, b := range buf {
if b == 0 {
result = append(result, string(buf[off:i]))
off = i + 1
}
}
return result
}

View file

@ -295,3 +295,18 @@ func TestCapRightsSetAndClear(t *testing.T) {
t.Fatalf("Wrong rights set")
}
}
// stringsFromByteSlice converts a sequence of attributes to a []string.
// On FreeBSD, each entry consists of a single byte containing the length
// of the attribute name, followed by the attribute name.
// The name is _not_ NULL-terminated.
func stringsFromByteSlice(buf []byte) []string {
var result []string
i := 0
for i < len(buf) {
next := i + 1 + int(buf[i])
result = append(result, string(buf[i+1:next]))
i = next
}
return result
}

Some files were not shown because too many files have changed in this diff Show more