diff options
Diffstat (limited to 'vendor/github.com/smallstep')
124 files changed, 742 insertions, 15659 deletions
diff --git a/vendor/github.com/smallstep/certificates/acme/account.go b/vendor/github.com/smallstep/certificates/acme/account.go index 246e031..38cca21 100644 --- a/vendor/github.com/smallstep/certificates/acme/account.go +++ b/vendor/github.com/smallstep/certificates/acme/account.go @@ -21,7 +21,6 @@ type Account struct { OrdersURL string `json:"orders"` ExternalAccountBinding interface{} `json:"externalAccountBinding,omitempty"` LocationPrefix string `json:"-"` - ProvisionerID string `json:"-"` ProvisionerName string `json:"-"` } diff --git a/vendor/github.com/smallstep/certificates/acme/api/account.go b/vendor/github.com/smallstep/certificates/acme/api/account.go index 3114dcb..25d923c 100644 --- a/vendor/github.com/smallstep/certificates/acme/api/account.go +++ b/vendor/github.com/smallstep/certificates/acme/api/account.go @@ -82,23 +82,23 @@ func NewAccount(w http.ResponseWriter, r *http.Request) { payload, err := payloadFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } var nar NewAccountRequest if err := json.Unmarshal(payload.value, &nar); err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "failed to unmarshal new-account request payload")) return } if err := nar.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } prov, err := acmeProvisionerFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -108,26 +108,26 @@ func NewAccount(w http.ResponseWriter, r *http.Request) { var acmeErr *acme.Error if !errors.As(err, &acmeErr) || acmeErr.Status != http.StatusBadRequest { // Something went wrong ... - render.Error(w, r, err) + render.Error(w, err) return } // Account does not exist // if nar.OnlyReturnExisting { - render.Error(w, r, acme.NewError(acme.ErrorAccountDoesNotExistType, + render.Error(w, acme.NewError(acme.ErrorAccountDoesNotExistType, "account does not exist")) return } jwk, err := jwkFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } eak, err := validateExternalAccountBinding(ctx, &nar) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -136,21 +136,20 @@ func NewAccount(w http.ResponseWriter, r *http.Request) { Contact: nar.Contact, Status: acme.StatusValid, LocationPrefix: getAccountLocationPath(ctx, linker, ""), - ProvisionerID: prov.ID, - ProvisionerName: prov.Name, + ProvisionerName: prov.GetName(), } if err := db.CreateAccount(ctx, acc); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error creating account")) + render.Error(w, acme.WrapErrorISE(err, "error creating account")) return } if eak != nil { // means that we have a (valid) External Account Binding key that should be bound, updated and sent in the response if err := eak.BindTo(acc); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } if err := db.UpdateExternalAccountKey(ctx, prov.ID, eak); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error updating external account binding key")) + render.Error(w, acme.WrapErrorISE(err, "error updating external account binding key")) return } acc.ExternalAccountBinding = nar.ExternalAccountBinding @@ -163,7 +162,7 @@ func NewAccount(w http.ResponseWriter, r *http.Request) { linker.LinkAccount(ctx, acc) w.Header().Set("Location", getAccountLocationPath(ctx, linker, acc.ID)) - render.JSONStatus(w, r, acc, httpStatus) + render.JSONStatus(w, acc, httpStatus) } // GetOrUpdateAccount is the api for updating an ACME account. @@ -174,12 +173,12 @@ func GetOrUpdateAccount(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } payload, err := payloadFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -188,12 +187,12 @@ func GetOrUpdateAccount(w http.ResponseWriter, r *http.Request) { if !payload.isPostAsGet { var uar UpdateAccountRequest if err := json.Unmarshal(payload.value, &uar); err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "failed to unmarshal new-account request payload")) return } if err := uar.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } if len(uar.Status) > 0 || len(uar.Contact) > 0 { @@ -204,7 +203,7 @@ func GetOrUpdateAccount(w http.ResponseWriter, r *http.Request) { } if err := db.UpdateAccount(ctx, acc); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error updating account")) + render.Error(w, acme.WrapErrorISE(err, "error updating account")) return } } @@ -213,7 +212,7 @@ func GetOrUpdateAccount(w http.ResponseWriter, r *http.Request) { linker.LinkAccount(ctx, acc) w.Header().Set("Location", linker.GetLink(ctx, acme.AccountLinkType, acc.ID)) - render.JSON(w, r, acc) + render.JSON(w, acc) } func logOrdersByAccount(w http.ResponseWriter, oids []string) { @@ -233,23 +232,23 @@ func GetOrdersByAccountID(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } accID := chi.URLParam(r, "accID") if acc.ID != accID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, "account ID '%s' does not match url param '%s'", acc.ID, accID)) + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account ID '%s' does not match url param '%s'", acc.ID, accID)) return } orders, err := db.GetOrdersByAccountID(ctx, acc.ID) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } linker.LinkOrdersByAccountID(ctx, orders) - render.JSON(w, r, orders) + render.JSON(w, orders) logOrdersByAccount(w, orders) } diff --git a/vendor/github.com/smallstep/certificates/acme/api/handler.go b/vendor/github.com/smallstep/certificates/acme/api/handler.go index 0722bd9..d2940f4 100644 --- a/vendor/github.com/smallstep/certificates/acme/api/handler.go +++ b/vendor/github.com/smallstep/certificates/acme/api/handler.go @@ -223,13 +223,13 @@ func GetDirectory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() acmeProv, err := acmeProvisionerFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } linker := acme.MustLinkerFromContext(ctx) - render.JSON(w, r, &Directory{ + render.JSON(w, &Directory{ NewNonce: linker.GetLink(ctx, acme.NewNonceLinkType), NewAccount: linker.GetLink(ctx, acme.NewAccountLinkType), NewOrder: linker.GetLink(ctx, acme.NewOrderLinkType), @@ -273,8 +273,8 @@ func shouldAddMetaObject(p *provisioner.ACME) bool { // NotImplemented returns a 501 and is generally a placeholder for functionality which // MAY be added at some point in the future but is not in any way a guarantee of such. -func NotImplemented(w http.ResponseWriter, r *http.Request) { - render.Error(w, r, acme.NewError(acme.ErrorNotImplementedType, "this API is not implemented")) +func NotImplemented(w http.ResponseWriter, _ *http.Request) { + render.Error(w, acme.NewError(acme.ErrorNotImplementedType, "this API is not implemented")) } // GetAuthorization ACME api for retrieving an Authz. @@ -285,28 +285,28 @@ func GetAuthorization(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } az, err := db.GetAuthorization(ctx, chi.URLParam(r, "authzID")) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving authorization")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving authorization")) return } if acc.ID != az.AccountID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account '%s' does not own authorization '%s'", acc.ID, az.ID)) return } if err = az.UpdateStatus(ctx, db); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error updating authorization status")) + render.Error(w, acme.WrapErrorISE(err, "error updating authorization status")) return } linker.LinkAuthorization(ctx, az) w.Header().Set("Location", linker.GetLink(ctx, acme.AuthzLinkType, az.ID)) - render.JSON(w, r, az) + render.JSON(w, az) } // GetChallenge ACME api for retrieving a Challenge. @@ -317,13 +317,13 @@ func GetChallenge(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } payload, err := payloadFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -336,22 +336,22 @@ func GetChallenge(w http.ResponseWriter, r *http.Request) { azID := chi.URLParam(r, "authzID") ch, err := db.GetChallenge(ctx, chi.URLParam(r, "chID"), azID) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving challenge")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving challenge")) return } ch.AuthorizationID = azID if acc.ID != ch.AccountID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account '%s' does not own challenge '%s'", acc.ID, ch.ID)) return } jwk, err := jwkFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } if err = ch.Validate(ctx, db, jwk, payload.value); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error validating challenge")) + render.Error(w, acme.WrapErrorISE(err, "error validating challenge")) return } @@ -359,7 +359,7 @@ func GetChallenge(w http.ResponseWriter, r *http.Request) { w.Header().Add("Link", link(linker.GetLink(ctx, acme.AuthzLinkType, azID), "up")) w.Header().Set("Location", linker.GetLink(ctx, acme.ChallengeLinkType, azID, ch.ID)) - render.JSON(w, r, ch) + render.JSON(w, ch) } // GetCertificate ACME api for retrieving a Certificate. @@ -369,18 +369,18 @@ func GetCertificate(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } certID := chi.URLParam(r, "certID") cert, err := db.GetCertificate(ctx, certID) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving certificate")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving certificate")) return } if cert.AccountID != acc.ID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account '%s' does not own certificate '%s'", acc.ID, certID)) return } diff --git a/vendor/github.com/smallstep/certificates/acme/api/middleware.go b/vendor/github.com/smallstep/certificates/acme/api/middleware.go index 628da7e..afccca7 100644 --- a/vendor/github.com/smallstep/certificates/acme/api/middleware.go +++ b/vendor/github.com/smallstep/certificates/acme/api/middleware.go @@ -36,7 +36,7 @@ func addNonce(next nextHTTP) nextHTTP { db := acme.MustDatabaseFromContext(r.Context()) nonce, err := db.CreateNonce(r.Context()) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } w.Header().Set("Replay-Nonce", string(nonce)) @@ -64,7 +64,7 @@ func verifyContentType(next nextHTTP) nextHTTP { return func(w http.ResponseWriter, r *http.Request) { p, err := provisionerFromContext(r.Context()) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -88,7 +88,7 @@ func verifyContentType(next nextHTTP) nextHTTP { return } } - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, + render.Error(w, acme.NewError(acme.ErrorMalformedType, "expected content-type to be in %s, but got %s", expected, ct)) } } @@ -98,12 +98,12 @@ func parseJWS(next nextHTTP) nextHTTP { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "failed to read request body")) + render.Error(w, acme.WrapErrorISE(err, "failed to read request body")) return } jws, err := jose.ParseJWS(string(body)) if err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, "failed to parse JWS from request body")) + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "failed to parse JWS from request body")) return } ctx := context.WithValue(r.Context(), jwsContextKey, jws) @@ -133,15 +133,15 @@ func validateJWS(next nextHTTP) nextHTTP { jws, err := jwsFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } if len(jws.Signatures) == 0 { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "request body does not contain a signature")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "request body does not contain a signature")) return } if len(jws.Signatures) > 1 { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "request body contains more than one signature")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "request body contains more than one signature")) return } @@ -152,7 +152,7 @@ func validateJWS(next nextHTTP) nextHTTP { uh.Algorithm != "" || uh.Nonce != "" || len(uh.ExtraHeaders) > 0 { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "unprotected header must not be used")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "unprotected header must not be used")) return } hdr := sig.Protected @@ -162,13 +162,13 @@ func validateJWS(next nextHTTP) nextHTTP { switch k := hdr.JSONWebKey.Key.(type) { case *rsa.PublicKey: if k.Size() < keyutil.MinRSAKeyBytes { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, + render.Error(w, acme.NewError(acme.ErrorMalformedType, "rsa keys must be at least %d bits (%d bytes) in size", 8*keyutil.MinRSAKeyBytes, keyutil.MinRSAKeyBytes)) return } default: - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, + render.Error(w, acme.NewError(acme.ErrorMalformedType, "jws key type and algorithm do not match")) return } @@ -176,35 +176,35 @@ func validateJWS(next nextHTTP) nextHTTP { case jose.ES256, jose.ES384, jose.ES512, jose.EdDSA: // we good default: - render.Error(w, r, acme.NewError(acme.ErrorBadSignatureAlgorithmType, "unsuitable algorithm: %s", hdr.Algorithm)) + render.Error(w, acme.NewError(acme.ErrorBadSignatureAlgorithmType, "unsuitable algorithm: %s", hdr.Algorithm)) return } // Check the validity/freshness of the Nonce. if err := db.DeleteNonce(ctx, acme.Nonce(hdr.Nonce)); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } // Check that the JWS url matches the requested url. jwsURL, ok := hdr.ExtraHeaders["url"].(string) if !ok { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "jws missing url protected header")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "jws missing url protected header")) return } reqURL := &url.URL{Scheme: "https", Host: r.Host, Path: r.URL.Path} if jwsURL != reqURL.String() { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, + render.Error(w, acme.NewError(acme.ErrorMalformedType, "url header in JWS (%s) does not match request url (%s)", jwsURL, reqURL)) return } if hdr.JSONWebKey != nil && hdr.KeyID != "" { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "jwk and kid are mutually exclusive")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "jwk and kid are mutually exclusive")) return } if hdr.JSONWebKey == nil && hdr.KeyID == "" { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "either jwk or kid must be defined in jws protected header")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "either jwk or kid must be defined in jws protected header")) return } next(w, r) @@ -221,23 +221,23 @@ func extractJWK(next nextHTTP) nextHTTP { jws, err := jwsFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } jwk := jws.Signatures[0].Protected.JSONWebKey if jwk == nil { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "jwk expected in protected header")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "jwk expected in protected header")) return } if !jwk.Valid() { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "invalid jwk in protected header")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "invalid jwk in protected header")) return } // Overwrite KeyID with the JWK thumbprint. jwk.KeyID, err = acme.KeyToID(jwk) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error getting KeyID from JWK")) + render.Error(w, acme.WrapErrorISE(err, "error getting KeyID from JWK")) return } @@ -247,15 +247,15 @@ func extractJWK(next nextHTTP) nextHTTP { // Get Account OR continue to generate a new one OR continue Revoke with certificate private key acc, err := db.GetAccountByKeyID(ctx, jwk.KeyID) switch { - case acme.IsErrNotFound(err): + case errors.Is(err, acme.ErrNotFound): // For NewAccount and Revoke requests ... break case err != nil: - render.Error(w, r, err) + render.Error(w, err) return default: if !acc.IsValid() { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, "account is not active")) + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account is not active")) return } ctx = context.WithValue(ctx, accContextKey, acc) @@ -274,11 +274,11 @@ func checkPrerequisites(next nextHTTP) nextHTTP { if ok { ok, err := checkFunc(ctx) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error checking acme provisioner prerequisites")) + render.Error(w, acme.WrapErrorISE(err, "error checking acme provisioner prerequisites")) return } if !ok { - render.Error(w, r, acme.NewError(acme.ErrorNotImplementedType, "acme provisioner configuration lacks prerequisites")) + render.Error(w, acme.NewError(acme.ErrorNotImplementedType, "acme provisioner configuration lacks prerequisites")) return } } @@ -296,13 +296,13 @@ func lookupJWK(next nextHTTP) nextHTTP { jws, err := jwsFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } kid := jws.Signatures[0].Protected.KeyID if kid == "" { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "signature missing 'kid'")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "signature missing 'kid'")) return } @@ -310,14 +310,14 @@ func lookupJWK(next nextHTTP) nextHTTP { acc, err := db.GetAccount(ctx, accID) switch { case acme.IsErrNotFound(err): - render.Error(w, r, acme.NewError(acme.ErrorAccountDoesNotExistType, "account with ID '%s' not found", accID)) + render.Error(w, acme.NewError(acme.ErrorAccountDoesNotExistType, "account with ID '%s' not found", accID)) return case err != nil: - render.Error(w, r, err) + render.Error(w, err) return default: if !acc.IsValid() { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, "account is not active")) + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account is not active")) return } @@ -325,7 +325,7 @@ func lookupJWK(next nextHTTP) nextHTTP { if kid != storedLocation { // ACME accounts should have a stored location equivalent to the // kid in the ACME request. - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "kid does not match stored account location; expected %s, but got %s", storedLocation, kid)) return @@ -334,16 +334,14 @@ func lookupJWK(next nextHTTP) nextHTTP { // Verify that the provisioner with which the account was created // matches the provisioner in the request URL. reqProv := acme.MustProvisionerFromContext(ctx) - switch { - case acc.ProvisionerID == "" && acc.ProvisionerName != reqProv.GetName(): - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, - "account provisioner does not match requested provisioner; account provisioner = %s, requested provisioner = %s", - acc.ProvisionerName, reqProv.GetName())) - return - case acc.ProvisionerID != "" && acc.ProvisionerID != reqProv.GetID(): - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + reqProvName := reqProv.GetName() + accProvName := acc.ProvisionerName + if reqProvName != accProvName { + // Provisioner in the URL must match the provisioner with + // which the account was created. + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account provisioner does not match requested provisioner; account provisioner = %s, requested provisioner = %s", - acc.ProvisionerID, reqProv.GetID())) + accProvName, reqProvName)) return } } else { @@ -355,7 +353,7 @@ func lookupJWK(next nextHTTP) nextHTTP { linker := acme.MustLinkerFromContext(ctx) kidPrefix := linker.GetLink(ctx, acme.AccountLinkType, "") if !strings.HasPrefix(kid, kidPrefix) { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, + render.Error(w, acme.NewError(acme.ErrorMalformedType, "kid does not have required prefix; expected %s, but got %s", kidPrefix, kid)) return @@ -376,7 +374,7 @@ func extractOrLookupJWK(next nextHTTP) nextHTTP { ctx := r.Context() jws, err := jwsFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -412,16 +410,16 @@ func verifyAndExtractJWSPayload(next nextHTTP) nextHTTP { ctx := r.Context() jws, err := jwsFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } jwk, err := jwkFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } if jwk.Algorithm != "" && jwk.Algorithm != jws.Signatures[0].Protected.Algorithm { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "verifier and signature algorithm do not match")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "verifier and signature algorithm do not match")) return } @@ -430,11 +428,11 @@ func verifyAndExtractJWSPayload(next nextHTTP) nextHTTP { case errors.Is(err, jose.ErrCryptoFailure): payload, err = retryVerificationWithPatchedSignatures(jws, jwk) if err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, "error verifying jws with patched signature(s)")) + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "error verifying jws with patched signature(s)")) return } case err != nil: - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, "error verifying jws")) + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "error verifying jws")) return } @@ -551,11 +549,11 @@ func isPostAsGet(next nextHTTP) nextHTTP { return func(w http.ResponseWriter, r *http.Request) { payload, err := payloadFromContext(r.Context()) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } if !payload.isPostAsGet { - render.Error(w, r, acme.NewError(acme.ErrorMalformedType, "expected POST-as-GET")) + render.Error(w, acme.NewError(acme.ErrorMalformedType, "expected POST-as-GET")) return } next(w, r) diff --git a/vendor/github.com/smallstep/certificates/acme/api/order.go b/vendor/github.com/smallstep/certificates/acme/api/order.go index a75a4d8..b207f87 100644 --- a/vendor/github.com/smallstep/certificates/acme/api/order.go +++ b/vendor/github.com/smallstep/certificates/acme/api/order.go @@ -5,7 +5,6 @@ import ( "crypto/x509" "encoding/base64" "encoding/json" - "fmt" "net" "net/http" "strings" @@ -17,7 +16,6 @@ import ( "go.step.sm/crypto/x509util" "github.com/smallstep/certificates/acme" - "github.com/smallstep/certificates/acme/wire" "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/authority/policy" "github.com/smallstep/certificates/authority/provisioner" @@ -50,86 +48,16 @@ func (n *NewOrderRequest) Validate() error { if id.Value == "" { return acme.NewError(acme.ErrorMalformedType, "permanent identifier cannot be empty") } - case acme.WireUser, acme.WireDevice: - // validation of Wire identifiers is performed in `validateWireIdentifiers`, but - // marked here as known and supported types. - continue default: return acme.NewError(acme.ErrorMalformedType, "identifier type unsupported: %s", id.Type) } - } - if err := n.validateWireIdentifiers(); err != nil { - return acme.WrapError(acme.ErrorMalformedType, err, "failed validating Wire identifiers") + // TODO(hs): add some validations for DNS domains? + // TODO(hs): combine the errors from this with allow/deny policy, like example error in https://datatracker.ietf.org/doc/html/rfc8555#section-6.7.1 } - - // TODO(hs): add some validations for DNS domains? - // TODO(hs): combine the errors from this with allow/deny policy, like example error in https://datatracker.ietf.org/doc/html/rfc8555#section-6.7.1 - return nil } -func (n *NewOrderRequest) validateWireIdentifiers() error { - if !n.hasWireIdentifiers() { - return nil - } - - userIdentifiers := identifiersOfType(acme.WireUser, n.Identifiers) - deviceIdentifiers := identifiersOfType(acme.WireDevice, n.Identifiers) - - if len(userIdentifiers) != 1 { - return fmt.Errorf("expected exactly one Wire UserID identifier; got %d", len(userIdentifiers)) - } - if len(deviceIdentifiers) != 1 { - return fmt.Errorf("expected exactly one Wire DeviceID identifier, got %d", len(deviceIdentifiers)) - } - - wireUserID, err := wire.ParseUserID(userIdentifiers[0].Value) - if err != nil { - return fmt.Errorf("failed parsing Wire UserID: %w", err) - } - - wireDeviceID, err := wire.ParseDeviceID(deviceIdentifiers[0].Value) - if err != nil { - return fmt.Errorf("failed parsing Wire DeviceID: %w", err) - } - if _, err := wire.ParseClientID(wireDeviceID.ClientID); err != nil { - return fmt.Errorf("invalid Wire client ID %q: %w", wireDeviceID.ClientID, err) - } - - switch { - case wireUserID.Domain != wireDeviceID.Domain: - return fmt.Errorf("UserID domain %q does not match DeviceID domain %q", wireUserID.Domain, wireDeviceID.Domain) - case wireUserID.Name != wireDeviceID.Name: - return fmt.Errorf("UserID name %q does not match DeviceID name %q", wireUserID.Name, wireDeviceID.Name) - case wireUserID.Handle != wireDeviceID.Handle: - return fmt.Errorf("UserID handle %q does not match DeviceID handle %q", wireUserID.Handle, wireDeviceID.Handle) - } - - return nil -} - -// hasWireIdentifiers returns whether the [NewOrderRequest] contains -// Wire identifiers. -func (n *NewOrderRequest) hasWireIdentifiers() bool { - for _, i := range n.Identifiers { - if i.Type == acme.WireUser || i.Type == acme.WireDevice { - return true - } - } - return false -} - -// identifiersOfType returns the Identifiers that are of type typ. -func identifiersOfType(typ acme.IdentifierType, ids []acme.Identifier) (result []acme.Identifier) { - for _, id := range ids { - if id.Type == typ { - result = append(result, id) - } - } - return -} - // FinalizeRequest captures the body for a Finalize order request. type FinalizeRequest struct { CSR string `json:"csr"` @@ -171,29 +99,29 @@ func NewOrder(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } prov, err := provisionerFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } payload, err := payloadFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } var nor NewOrderRequest if err := json.Unmarshal(payload.value, &nor); err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "failed to unmarshal new-order request payload")) return } if err := nor.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -202,39 +130,39 @@ func NewOrder(w http.ResponseWriter, r *http.Request) { acmeProv, err := acmeProvisionerFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } var eak *acme.ExternalAccountKey if acmeProv.RequireEAB { if eak, err = db.GetExternalAccountKeyByAccountID(ctx, prov.GetID(), acc.ID); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving external account binding key")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving external account binding key")) return } } acmePolicy, err := newACMEPolicyEngine(eak) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error creating ACME policy engine")) + render.Error(w, acme.WrapErrorISE(err, "error creating ACME policy engine")) return } for _, identifier := range nor.Identifiers { // evaluate the ACME account level policy if err = isIdentifierAllowed(acmePolicy, identifier); err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized")) + render.Error(w, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized")) return } // evaluate the provisioner level policy orderIdentifier := provisioner.ACMEIdentifier{Type: provisioner.ACMEIdentifierType(identifier.Type), Value: identifier.Value} if err = prov.AuthorizeOrderIdentifier(ctx, orderIdentifier); err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized")) + render.Error(w, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized")) return } // evaluate the authority level policy if err = ca.AreSANsAllowed(ctx, []string{identifier.Value}); err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized")) + render.Error(w, acme.WrapError(acme.ErrorRejectedIdentifierType, err, "not authorized")) return } } @@ -260,7 +188,7 @@ func NewOrder(w http.ResponseWriter, r *http.Request) { Status: acme.StatusPending, } if err := newAuthorization(ctx, az); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } o.AuthorizationIDs[i] = az.ID @@ -279,14 +207,14 @@ func NewOrder(w http.ResponseWriter, r *http.Request) { } if err := db.CreateOrder(ctx, o); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error creating order")) + render.Error(w, acme.WrapErrorISE(err, "error creating order")) return } linker.LinkOrder(ctx, o) w.Header().Set("Location", linker.GetLink(ctx, acme.OrderLinkType, o.ID)) - render.JSONStatus(w, r, o, http.StatusCreated) + render.JSONStatus(w, o, http.StatusCreated) } func isIdentifierAllowed(acmePolicy policy.X509Policy, identifier acme.Identifier) error { @@ -298,7 +226,6 @@ func isIdentifierAllowed(acmePolicy policy.X509Policy, identifier acme.Identifie func newACMEPolicyEngine(eak *acme.ExternalAccountKey) (policy.X509Policy, error) { if eak == nil { - //nolint:nilnil,nolintlint // expected values return nil, nil } return policy.NewX509PolicyEngine(eak.Policy) @@ -335,43 +262,12 @@ func newAuthorization(ctx context.Context, az *acme.Authorization) error { continue } - var target string - switch az.Identifier.Type { - case acme.WireUser: - wireOptions, err := prov.GetOptions().GetWireOptions() - if err != nil { - return acme.WrapErrorISE(err, "failed getting Wire options") - } - target, err = wireOptions.GetOIDCOptions().EvaluateTarget("") // TODO(hs): determine if required by Wire - if err != nil { - return acme.WrapError(acme.ErrorMalformedType, err, "invalid Go template registered for 'target'") - } - case acme.WireDevice: - wireID, err := wire.ParseDeviceID(az.Identifier.Value) - if err != nil { - return acme.WrapError(acme.ErrorMalformedType, err, "failed parsing WireDevice") - } - clientID, err := wire.ParseClientID(wireID.ClientID) - if err != nil { - return acme.WrapError(acme.ErrorMalformedType, err, "failed parsing ClientID") - } - wireOptions, err := prov.GetOptions().GetWireOptions() - if err != nil { - return acme.WrapErrorISE(err, "failed getting Wire options") - } - target, err = wireOptions.GetDPOPOptions().EvaluateTarget(clientID.DeviceID) - if err != nil { - return acme.WrapError(acme.ErrorMalformedType, err, "invalid Go template registered for 'target'") - } - } - ch := &acme.Challenge{ AccountID: az.AccountID, Value: az.Identifier.Value, Type: typ, Token: az.Token, Status: acme.StatusPending, - Target: target, } if err := db.CreateChallenge(ctx, ch); err != nil { return acme.WrapErrorISE(err, "error creating challenge") @@ -392,39 +288,39 @@ func GetOrder(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } prov, err := provisionerFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } o, err := db.GetOrder(ctx, chi.URLParam(r, "ordID")) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving order")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving order")) return } if acc.ID != o.AccountID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account '%s' does not own order '%s'", acc.ID, o.ID)) return } if prov.GetID() != o.ProvisionerID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "provisioner '%s' does not own order '%s'", prov.GetID(), o.ID)) return } if err = o.UpdateStatus(ctx, db); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error updating order status")) + render.Error(w, acme.WrapErrorISE(err, "error updating order status")) return } linker.LinkOrder(ctx, o) w.Header().Set("Location", linker.GetLink(ctx, acme.OrderLinkType, o.ID)) - render.JSON(w, r, o) + render.JSON(w, o) } // FinalizeOrder attempts to finalize an order and create a certificate. @@ -435,56 +331,56 @@ func FinalizeOrder(w http.ResponseWriter, r *http.Request) { acc, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } prov, err := provisionerFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } payload, err := payloadFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } var fr FinalizeRequest if err := json.Unmarshal(payload.value, &fr); err != nil { - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "failed to unmarshal finalize-order request payload")) return } if err := fr.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } o, err := db.GetOrder(ctx, chi.URLParam(r, "ordID")) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving order")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving order")) return } if acc.ID != o.AccountID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "account '%s' does not own order '%s'", acc.ID, o.ID)) return } if prov.GetID() != o.ProvisionerID { - render.Error(w, r, acme.NewError(acme.ErrorUnauthorizedType, + render.Error(w, acme.NewError(acme.ErrorUnauthorizedType, "provisioner '%s' does not own order '%s'", prov.GetID(), o.ID)) return } ca := mustAuthority(ctx) if err = o.Finalize(ctx, db, fr.csr, ca, prov); err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error finalizing order")) + render.Error(w, acme.WrapErrorISE(err, "error finalizing order")) return } linker.LinkOrder(ctx, o) w.Header().Set("Location", linker.GetLink(ctx, acme.OrderLinkType, o.ID)) - render.JSON(w, r, o) + render.JSON(w, o) } // challengeTypes determines the types of challenges that should be used @@ -503,10 +399,6 @@ func challengeTypes(az *acme.Authorization) []acme.ChallengeType { } case acme.PermanentIdentifier: chTypes = []acme.ChallengeType{acme.DEVICEATTEST01} - case acme.WireUser: - chTypes = []acme.ChallengeType{acme.WIREOIDC01} - case acme.WireDevice: - chTypes = []acme.ChallengeType{acme.WIREDPOP01} default: chTypes = []acme.ChallengeType{} } diff --git a/vendor/github.com/smallstep/certificates/acme/api/revoke.go b/vendor/github.com/smallstep/certificates/acme/api/revoke.go index c613df2..270a9fb 100644 --- a/vendor/github.com/smallstep/certificates/acme/api/revoke.go +++ b/vendor/github.com/smallstep/certificates/acme/api/revoke.go @@ -33,65 +33,65 @@ func RevokeCert(w http.ResponseWriter, r *http.Request) { jws, err := jwsFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } prov, err := provisionerFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } payload, err := payloadFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } var p revokePayload err = json.Unmarshal(payload.value, &p) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error unmarshaling payload")) + render.Error(w, acme.WrapErrorISE(err, "error unmarshaling payload")) return } certBytes, err := base64.RawURLEncoding.DecodeString(p.Certificate) if err != nil { // in this case the most likely cause is a client that didn't properly encode the certificate - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, "error base64url decoding payload certificate property")) + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "error base64url decoding payload certificate property")) return } certToBeRevoked, err := x509.ParseCertificate(certBytes) if err != nil { // in this case a client may have encoded something different than a certificate - render.Error(w, r, acme.WrapError(acme.ErrorMalformedType, err, "error parsing certificate")) + render.Error(w, acme.WrapError(acme.ErrorMalformedType, err, "error parsing certificate")) return } serial := certToBeRevoked.SerialNumber.String() dbCert, err := db.GetCertificateBySerial(ctx, serial) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving certificate by serial")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving certificate by serial")) return } if !bytes.Equal(dbCert.Leaf.Raw, certToBeRevoked.Raw) { // this should never happen - render.Error(w, r, acme.NewErrorISE("certificate raw bytes are not equal")) + render.Error(w, acme.NewErrorISE("certificate raw bytes are not equal")) return } if shouldCheckAccountFrom(jws) { account, err := accountFromContext(ctx) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } acmeErr := isAccountAuthorized(ctx, dbCert, certToBeRevoked, account) if acmeErr != nil { - render.Error(w, r, acmeErr) + render.Error(w, acmeErr) return } } else { @@ -100,7 +100,7 @@ func RevokeCert(w http.ResponseWriter, r *http.Request) { _, err := jws.Verify(certToBeRevoked.PublicKey) if err != nil { // TODO(hs): possible to determine an error vs. unauthorized and thus provide an ISE vs. Unauthorized? - render.Error(w, r, wrapUnauthorizedError(certToBeRevoked, nil, "verification of jws using certificate public key failed", err)) + render.Error(w, wrapUnauthorizedError(certToBeRevoked, nil, "verification of jws using certificate public key failed", err)) return } } @@ -108,19 +108,19 @@ func RevokeCert(w http.ResponseWriter, r *http.Request) { ca := mustAuthority(ctx) hasBeenRevokedBefore, err := ca.IsRevoked(serial) if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error retrieving revocation status of certificate")) + render.Error(w, acme.WrapErrorISE(err, "error retrieving revocation status of certificate")) return } if hasBeenRevokedBefore { - render.Error(w, r, acme.NewError(acme.ErrorAlreadyRevokedType, "certificate was already revoked")) + render.Error(w, acme.NewError(acme.ErrorAlreadyRevokedType, "certificate was already revoked")) return } reasonCode := p.ReasonCode acmeErr := validateReasonCode(reasonCode) if acmeErr != nil { - render.Error(w, r, acmeErr) + render.Error(w, acmeErr) return } @@ -128,14 +128,14 @@ func RevokeCert(w http.ResponseWriter, r *http.Request) { ctx = provisioner.NewContextWithMethod(ctx, provisioner.RevokeMethod) err = prov.AuthorizeRevoke(ctx, "") if err != nil { - render.Error(w, r, acme.WrapErrorISE(err, "error authorizing revocation on provisioner")) + render.Error(w, acme.WrapErrorISE(err, "error authorizing revocation on provisioner")) return } options := revokeOptions(serial, certToBeRevoked, reasonCode) err = ca.Revoke(ctx, options) if err != nil { - render.Error(w, r, wrapRevokeErr(err)) + render.Error(w, wrapRevokeErr(err)) return } @@ -180,7 +180,7 @@ func isAccountAuthorized(_ context.Context, dbCert *acme.Certificate, certToBeRe func wrapRevokeErr(err error) *acme.Error { t := err.Error() if strings.Contains(t, "is already revoked") { - return acme.NewError(acme.ErrorAlreadyRevokedType, t) //nolint:govet // allow non-constant error messages + return acme.NewError(acme.ErrorAlreadyRevokedType, t) } return acme.WrapErrorISE(err, "error when revoking certificate") } @@ -190,9 +190,9 @@ func wrapRevokeErr(err error) *acme.Error { func wrapUnauthorizedError(cert *x509.Certificate, unauthorizedIdentifiers []acme.Identifier, msg string, err error) *acme.Error { var acmeErr *acme.Error if err == nil { - acmeErr = acme.NewError(acme.ErrorUnauthorizedType, msg) //nolint:govet // allow non-constant error messages + acmeErr = acme.NewError(acme.ErrorUnauthorizedType, msg) } else { - acmeErr = acme.WrapError(acme.ErrorUnauthorizedType, err, msg) //nolint:govet // allow non-constant error messages + acmeErr = acme.WrapError(acme.ErrorUnauthorizedType, err, msg) } acmeErr.Status = http.StatusForbidden // RFC8555 7.6 shows example with 403 diff --git a/vendor/github.com/smallstep/certificates/acme/challenge.go b/vendor/github.com/smallstep/certificates/acme/challenge.go index cf658cf..9f3ca38 100644 --- a/vendor/github.com/smallstep/certificates/acme/challenge.go +++ b/vendor/github.com/smallstep/certificates/acme/challenge.go @@ -1,7 +1,6 @@ package acme import ( - "bytes" "context" "crypto" "crypto/ecdsa" @@ -26,19 +25,18 @@ import ( "strings" "time" - "github.com/coreos/go-oidc/v3/oidc" "github.com/fxamacker/cbor/v2" "github.com/google/go-tpm/legacy/tpm2" + "golang.org/x/exp/slices" + "github.com/smallstep/go-attestation/attest" + "go.step.sm/crypto/jose" "go.step.sm/crypto/keyutil" "go.step.sm/crypto/pemutil" "go.step.sm/crypto/x509util" - "golang.org/x/exp/slices" - "github.com/smallstep/certificates/acme/wire" "github.com/smallstep/certificates/authority/provisioner" - wireprovisioner "github.com/smallstep/certificates/authority/provisioner/wire" ) type ChallengeType string @@ -52,10 +50,6 @@ const ( TLSALPN01 ChallengeType = "tls-alpn-01" // DEVICEATTEST01 is the device-attest-01 ACME challenge type DEVICEATTEST01 ChallengeType = "device-attest-01" - // WIREOIDC01 is the Wire OIDC challenge type - WIREOIDC01 ChallengeType = "wire-oidc-01" - // WIREDPOP01 is the Wire DPoP challenge type - WIREDPOP01 ChallengeType = "wire-dpop-01" ) var ( @@ -68,11 +62,6 @@ var ( // // This variable can be used for testing purposes. InsecurePortTLSALPN01 int - - // StrictFQDN allows to enforce a fully qualified domain name in the DNS - // resolution. By default it allows domain resolution using a search list - // defined in the resolv.conf or similar configuration. - StrictFQDN bool ) // Challenge represents an ACME response Challenge type. @@ -86,7 +75,6 @@ type Challenge struct { Token string `json:"token"` ValidatedAt string `json:"validated,omitempty"` URL string `json:"url"` - Target string `json:"target,omitempty"` Error *Error `json:"error,omitempty"` } @@ -116,37 +104,22 @@ func (ch *Challenge) Validate(ctx context.Context, db DB, jwk *jose.JSONWebKey, return tlsalpn01Validate(ctx, ch, db, jwk) case DEVICEATTEST01: return deviceAttest01Validate(ctx, ch, db, jwk, payload) - case WIREOIDC01: - wireDB, ok := db.(WireDB) - if !ok { - return NewErrorISE("db %T is not a WireDB", db) - } - return wireOIDC01Validate(ctx, ch, wireDB, jwk, payload) - case WIREDPOP01: - wireDB, ok := db.(WireDB) - if !ok { - return NewErrorISE("db %T is not a WireDB", db) - } - return wireDPOP01Validate(ctx, ch, wireDB, jwk, payload) default: - return NewErrorISE("unexpected challenge type %q", ch.Type) + return NewErrorISE("unexpected challenge type '%s'", ch.Type) } } func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey) error { - u := &url.URL{Scheme: "http", Host: ch.Value, Path: fmt.Sprintf("/.well-known/acme-challenge/%s", ch.Token)} - challengeURL := &url.URL{Scheme: "http", Host: http01ChallengeHost(ch.Value), Path: fmt.Sprintf("/.well-known/acme-challenge/%s", ch.Token)} + u := &url.URL{Scheme: "http", Host: http01ChallengeHost(ch.Value), Path: fmt.Sprintf("/.well-known/acme-challenge/%s", ch.Token)} // Append insecure port if set. // Only used for testing purposes. if InsecurePortHTTP01 != 0 { - insecurePort := strconv.Itoa(InsecurePortHTTP01) - u.Host += ":" + insecurePort - challengeURL.Host += ":" + insecurePort + u.Host += ":" + strconv.Itoa(InsecurePortHTTP01) } vc := MustClientFromContext(ctx) - resp, err := vc.Get(challengeURL.String()) + resp, err := vc.Get(u.String()) if err != nil { return storeError(ctx, db, ch, false, WrapError(ErrorConnectionType, err, "error doing http GET for url %s", u)) @@ -184,42 +157,15 @@ func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWeb return nil } -// rootedName adds a trailing "." to a given domain name. -func rootedName(name string) string { - if StrictFQDN { - if name == "" || name[len(name)-1] != '.' { - return name + "." - } - } - return name -} - // http01ChallengeHost checks if a Challenge value is an IPv6 address // and adds square brackets if that's the case, so that it can be used // as a hostname. Returns the original Challenge value as the host to // use in other cases. func http01ChallengeHost(value string) string { - if ip := net.ParseIP(value); ip != nil { - if ip.To4() == nil { - value = "[" + value + "]" - } - return value - } - return rootedName(value) -} - -// tlsAlpn01ChallengeHost returns the rooted DNS used on TLS-ALPN-01 -// validations. -func tlsAlpn01ChallengeHost(name string) string { - if ip := net.ParseIP(name); ip != nil { - return name + if ip := net.ParseIP(value); ip != nil && ip.To4() == nil { + value = "[" + value + "]" } - return rootedName(name) -} - -// dns01ChallengeHost returns the TXT record used in DNS-01 validations. -func dns01ChallengeHost(domain string) string { - return "_acme-challenge." + rootedName(domain) + return value } func tlsAlert(err error) uint8 { @@ -244,12 +190,13 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON InsecureSkipVerify: true, //nolint:gosec // we expect a self-signed challenge certificate } + var hostPort string + // Allow to change TLS port for testing purposes. - hostPort := tlsAlpn01ChallengeHost(ch.Value) if port := InsecurePortTLSALPN01; port == 0 { - hostPort = net.JoinHostPort(hostPort, "443") + hostPort = net.JoinHostPort(ch.Value, "443") } else { - hostPort = net.JoinHostPort(hostPort, strconv.Itoa(port)) + hostPort = net.JoinHostPort(ch.Value, strconv.Itoa(port)) } vc := MustClientFromContext(ctx) @@ -264,7 +211,7 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON "cannot negotiate ALPN acme-tls/1 protocol for tls-alpn-01 challenge")) } return storeError(ctx, db, ch, false, WrapError(ErrorConnectionType, err, - "error doing TLS dial for %s", ch.Value)) + "error doing TLS dial for %s", hostPort)) } defer conn.Close() @@ -360,7 +307,7 @@ func dns01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebK domain := strings.TrimPrefix(ch.Value, "*.") vc := MustClientFromContext(ctx) - txtRecords, err := vc.LookupTxt(dns01ChallengeHost(domain)) + txtRecords, err := vc.LookupTxt("_acme-challenge." + domain) if err != nil { return storeError(ctx, db, ch, false, WrapError(ErrorDNSType, err, "error looking up TXT records for domain %s", domain)) @@ -395,387 +342,6 @@ func dns01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebK return nil } -type wireOidcPayload struct { - // IDToken contains the OIDC identity token - IDToken string `json:"id_token"` -} - -func wireOIDC01Validate(ctx context.Context, ch *Challenge, db WireDB, jwk *jose.JSONWebKey, payload []byte) error { - prov, ok := ProvisionerFromContext(ctx) - if !ok { - return NewErrorISE("missing provisioner") - } - wireOptions, err := prov.GetOptions().GetWireOptions() - if err != nil { - return WrapErrorISE(err, "failed getting Wire options") - } - linker, ok := LinkerFromContext(ctx) - if !ok { - return NewErrorISE("missing linker") - } - - var oidcPayload wireOidcPayload - if err := json.Unmarshal(payload, &oidcPayload); err != nil { - return WrapError(ErrorMalformedType, err, "error unmarshalling Wire OIDC challenge payload") - } - - wireID, err := wire.ParseUserID(ch.Value) - if err != nil { - return WrapErrorISE(err, "error unmarshalling challenge data") - } - - oidcOptions := wireOptions.GetOIDCOptions() - verifier, err := oidcOptions.GetVerifier(ctx) - if err != nil { - return WrapErrorISE(err, "no OIDC verifier available") - } - - idToken, err := verifier.Verify(ctx, oidcPayload.IDToken) - if err != nil { - return storeError(ctx, db, ch, true, WrapError(ErrorRejectedIdentifierType, err, - "error verifying ID token signature")) - } - - var claims struct { - Name string `json:"preferred_username,omitempty"` - Handle string `json:"name"` - Issuer string `json:"iss,omitempty"` - GivenName string `json:"given_name,omitempty"` - KeyAuth string `json:"keyauth"` - ACMEAudience string `json:"acme_aud,omitempty"` - } - if err := idToken.Claims(&claims); err != nil { - return storeError(ctx, db, ch, true, WrapError(ErrorRejectedIdentifierType, err, - "error retrieving claims from ID token")) - } - - // TODO(hs): move this into validation below? - expectedKeyAuth, err := KeyAuthorization(ch.Token, jwk) - if err != nil { - return WrapErrorISE(err, "error determining key authorization") - } - if expectedKeyAuth != claims.KeyAuth { - return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType, - "keyAuthorization does not match; expected %q, but got %q", expectedKeyAuth, claims.KeyAuth)) - } - - // audience is the full URL to the challenge - acmeAudience := linker.GetLink(ctx, ChallengeLinkType, ch.AuthorizationID, ch.ID) - if claims.ACMEAudience != acmeAudience { - return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType, - "invalid 'acme_aud' %q", claims.ACMEAudience)) - } - - transformedIDToken, err := validateWireOIDCClaims(oidcOptions, idToken, wireID) - if err != nil { - return storeError(ctx, db, ch, true, WrapError(ErrorRejectedIdentifierType, err, "claims in OIDC ID token don't match")) - } - - // Update and store the challenge. - ch.Status = StatusValid - ch.Error = nil - ch.ValidatedAt = clock.Now().Format(time.RFC3339) - - if err = db.UpdateChallenge(ctx, ch); err != nil { - return WrapErrorISE(err, "error updating challenge") - } - - orders, err := db.GetAllOrdersByAccountID(ctx, ch.AccountID) - if err != nil { - return WrapErrorISE(err, "could not retrieve current order by account id") - } - if len(orders) == 0 { - return NewErrorISE("there are not enough orders for this account for this custom OIDC challenge") - } - - order := orders[len(orders)-1] - if err := db.CreateOidcToken(ctx, order, transformedIDToken); err != nil { - return WrapErrorISE(err, "failed storing OIDC id token") - } - - return nil -} - -func validateWireOIDCClaims(o *wireprovisioner.OIDCOptions, token *oidc.IDToken, wireID wire.UserID) (map[string]any, error) { - var m map[string]any - if err := token.Claims(&m); err != nil { - return nil, fmt.Errorf("failed extracting OIDC ID token claims: %w", err) - } - transformed, err := o.Transform(m) - if err != nil { - return nil, fmt.Errorf("failed transforming OIDC ID token: %w", err) - } - - name, ok := transformed["name"] - if !ok { - return nil, fmt.Errorf("transformed OIDC ID token does not contain 'name'") - } - if wireID.Name != name { - return nil, fmt.Errorf("invalid 'name' %q after transformation", name) - } - - preferredUsername, ok := transformed["preferred_username"] - if !ok { - return nil, fmt.Errorf("transformed OIDC ID token does not contain 'preferred_username'") - } - if wireID.Handle != preferredUsername { - return nil, fmt.Errorf("invalid 'preferred_username' %q after transformation", preferredUsername) - } - - return transformed, nil -} - -type wireDpopPayload struct { - // AccessToken is the token generated by wire-server - AccessToken string `json:"access_token"` -} - -func wireDPOP01Validate(ctx context.Context, ch *Challenge, db WireDB, accountJWK *jose.JSONWebKey, payload []byte) error { - prov, ok := ProvisionerFromContext(ctx) - if !ok { - return NewErrorISE("missing provisioner") - } - wireOptions, err := prov.GetOptions().GetWireOptions() - if err != nil { - return WrapErrorISE(err, "failed getting Wire options") - } - linker, ok := LinkerFromContext(ctx) - if !ok { - return NewErrorISE("missing linker") - } - - var dpopPayload wireDpopPayload - if err := json.Unmarshal(payload, &dpopPayload); err != nil { - return WrapError(ErrorMalformedType, err, "error unmarshalling Wire DPoP challenge payload") - } - - wireID, err := wire.ParseDeviceID(ch.Value) - if err != nil { - return WrapErrorISE(err, "error unmarshalling challenge data") - } - - clientID, err := wire.ParseClientID(wireID.ClientID) - if err != nil { - return WrapErrorISE(err, "error parsing device id") - } - - dpopOptions := wireOptions.GetDPOPOptions() - issuer, err := dpopOptions.EvaluateTarget(clientID.DeviceID) - if err != nil { - return WrapErrorISE(err, "invalid Go template registered for 'target'") - } - - // audience is the full URL to the challenge - audience := linker.GetLink(ctx, ChallengeLinkType, ch.AuthorizationID, ch.ID) - - params := wireVerifyParams{ - token: dpopPayload.AccessToken, - tokenKey: dpopOptions.GetSigningKey(), - dpopKey: accountJWK.Public(), - dpopKeyID: accountJWK.KeyID, - issuer: issuer, - audience: audience, - wireID: wireID, - chToken: ch.Token, - t: clock.Now().UTC(), - } - _, dpop, err := parseAndVerifyWireAccessToken(params) - if err != nil { - return storeError(ctx, db, ch, true, WrapError(ErrorRejectedIdentifierType, err, - "failed validating Wire access token")) - } - - // Update and store the challenge. - ch.Status = StatusValid - ch.Error = nil - ch.ValidatedAt = clock.Now().Format(time.RFC3339) - - if err = db.UpdateChallenge(ctx, ch); err != nil { - return WrapErrorISE(err, "error updating challenge") - } - - orders, err := db.GetAllOrdersByAccountID(ctx, ch.AccountID) - if err != nil { - return WrapErrorISE(err, "could not find current order by account id") - } - if len(orders) == 0 { - return NewErrorISE("there are not enough orders for this account for this custom OIDC challenge") - } - - order := orders[len(orders)-1] - if err := db.CreateDpopToken(ctx, order, map[string]any(*dpop)); err != nil { - return WrapErrorISE(err, "failed storing DPoP token") - } - - return nil -} - -type wireCnf struct { - Kid string `json:"kid"` -} - -type wireAccessToken struct { - jose.Claims - Challenge string `json:"chal"` - Nonce string `json:"nonce"` - Cnf wireCnf `json:"cnf"` - Proof string `json:"proof"` - ClientID string `json:"client_id"` - APIVersion int `json:"api_version"` - Scope string `json:"scope"` -} - -type wireDpopJwt struct { - jose.Claims - ClientID string `json:"client_id"` - Challenge string `json:"chal"` - Nonce string `json:"nonce"` - HTU string `json:"htu"` -} - -type wireDpopToken map[string]any - -type wireVerifyParams struct { - token string - tokenKey crypto.PublicKey - dpopKey crypto.PublicKey - dpopKeyID string - issuer string - audience string - wireID wire.DeviceID - chToken string - t time.Time -} - -func parseAndVerifyWireAccessToken(v wireVerifyParams) (*wireAccessToken, *wireDpopToken, error) { - jwt, err := jose.ParseSigned(v.token) - if err != nil { - return nil, nil, fmt.Errorf("failed parsing token: %w", err) - } - - if len(jwt.Headers) != 1 { - return nil, nil, fmt.Errorf("token has wrong number of headers %d", len(jwt.Headers)) - } - keyID, err := KeyToID(&jose.JSONWebKey{Key: v.tokenKey}) - if err != nil { - return nil, nil, fmt.Errorf("failed calculating token key ID: %w", err) - } - jwtKeyID := jwt.Headers[0].KeyID - if jwtKeyID == "" { - if jwtKeyID, err = KeyToID(jwt.Headers[0].JSONWebKey); err != nil { - return nil, nil, fmt.Errorf("failed extracting token key ID: %w", err) - } - } - if jwtKeyID != keyID { - return nil, nil, fmt.Errorf("invalid token key ID %q", jwtKeyID) - } - - var accessToken wireAccessToken - if err = jwt.Claims(v.tokenKey, &accessToken); err != nil { - return nil, nil, fmt.Errorf("failed validating Wire DPoP token claims: %w", err) - } - - if err := accessToken.ValidateWithLeeway(jose.Expected{ - Time: v.t, - Issuer: v.issuer, - Audience: jose.Audience{v.audience}, - }, 1*time.Minute); err != nil { - return nil, nil, fmt.Errorf("failed validation: %w", err) - } - - if accessToken.Challenge == "" { - return nil, nil, errors.New("access token challenge 'chal' must not be empty") - } - if accessToken.Cnf.Kid == "" || accessToken.Cnf.Kid != v.dpopKeyID { - return nil, nil, fmt.Errorf("expected 'kid' %q; got %q", v.dpopKeyID, accessToken.Cnf.Kid) - } - if accessToken.ClientID != v.wireID.ClientID { - return nil, nil, fmt.Errorf("invalid Wire 'client_id' %q", accessToken.ClientID) - } - if accessToken.Expiry.Time().After(v.t.Add(time.Hour)) { - return nil, nil, fmt.Errorf("token expiry 'exp' %s is too far into the future", accessToken.Expiry.Time().String()) - } - if accessToken.Scope != "wire_client_id" { - return nil, nil, fmt.Errorf("invalid Wire 'scope' %q", accessToken.Scope) - } - - dpopJWT, err := jose.ParseSigned(accessToken.Proof) - if err != nil { - return nil, nil, fmt.Errorf("invalid Wire DPoP token: %w", err) - } - if len(dpopJWT.Headers) != 1 { - return nil, nil, fmt.Errorf("DPoP token has wrong number of headers %d", len(jwt.Headers)) - } - dpopJwtKeyID := dpopJWT.Headers[0].KeyID - if dpopJwtKeyID == "" { - if dpopJwtKeyID, err = KeyToID(dpopJWT.Headers[0].JSONWebKey); err != nil { - return nil, nil, fmt.Errorf("failed extracting DPoP token key ID: %w", err) - } - } - if dpopJwtKeyID != v.dpopKeyID { - return nil, nil, fmt.Errorf("invalid DPoP token key ID %q", dpopJWT.Headers[0].KeyID) - } - - var wireDpop wireDpopJwt - if err := dpopJWT.Claims(v.dpopKey, &wireDpop); err != nil { - return nil, nil, fmt.Errorf("failed validating Wire DPoP token claims: %w", err) - } - - if err := wireDpop.ValidateWithLeeway(jose.Expected{ - Time: v.t, - Audience: jose.Audience{v.audience}, - }, 1*time.Minute); err != nil { - return nil, nil, fmt.Errorf("failed DPoP validation: %w", err) - } - if wireDpop.HTU == "" || wireDpop.HTU != v.issuer { // DPoP doesn't contains "iss" claim, but has it in the "htu" claim - return nil, nil, fmt.Errorf("DPoP contains invalid issuer 'htu' %q", wireDpop.HTU) - } - if wireDpop.Expiry.Time().After(v.t.Add(time.Hour)) { - return nil, nil, fmt.Errorf("'exp' %s is too far into the future", wireDpop.Expiry.Time().String()) - } - if wireDpop.Subject != v.wireID.ClientID { - return nil, nil, fmt.Errorf("DPoP contains invalid Wire client ID %q", wireDpop.ClientID) - } - if wireDpop.Nonce == "" || wireDpop.Nonce != accessToken.Nonce { - return nil, nil, fmt.Errorf("DPoP contains invalid 'nonce' %q", wireDpop.Nonce) - } - if wireDpop.Challenge == "" || wireDpop.Challenge != accessToken.Challenge { - return nil, nil, fmt.Errorf("DPoP contains invalid challenge 'chal' %q", wireDpop.Challenge) - } - - // TODO(hs): can we use the wireDpopJwt and map that instead of doing Claims() twice? - var dpopToken wireDpopToken - if err := dpopJWT.Claims(v.dpopKey, &dpopToken); err != nil { - return nil, nil, fmt.Errorf("failed validating Wire DPoP token claims: %w", err) - } - - challenge, ok := dpopToken["chal"].(string) - if !ok { - return nil, nil, fmt.Errorf("invalid challenge 'chal' in Wire DPoP token") - } - if challenge == "" || challenge != v.chToken { - return nil, nil, fmt.Errorf("invalid Wire DPoP challenge 'chal' %q", challenge) - } - - handle, ok := dpopToken["handle"].(string) - if !ok { - return nil, nil, fmt.Errorf("invalid 'handle' in Wire DPoP token") - } - if handle == "" || handle != v.wireID.Handle { - return nil, nil, fmt.Errorf("invalid Wire client 'handle' %q", handle) - } - - name, ok := dpopToken["name"].(string) - if !ok { - return nil, nil, fmt.Errorf("invalid display 'name' in Wire DPoP token") - } - if name == "" || name != v.wireID.Name { - return nil, nil, fmt.Errorf("invalid Wire client display 'name' %q", name) - } - - return &accessToken, &dpopToken, nil -} - type payloadType struct { AttObj string `json:"attObj"` Error string `json:"error"` @@ -806,26 +372,12 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose attObj, err := base64.RawURLEncoding.DecodeString(p.AttObj) if err != nil { - return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "failed base64 decoding attObj %q", p.AttObj)) - } - - if len(attObj) == 0 || bytes.Equal(attObj, []byte("{}")) { - return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "attObj must not be empty")) - } - - cborDecoderOptions := cbor.DecOptions{} - cborDecoder, err := cborDecoderOptions.DecMode() - if err != nil { - return WrapErrorISE(err, "failed creating CBOR decoder") - } - - if err := cborDecoder.Wellformed(attObj); err != nil { - return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "attObj is not well formed CBOR: %v", err)) + return WrapErrorISE(err, "error base64 decoding attObj") } att := attestationObject{} - if err := cborDecoder.Unmarshal(attObj, &att); err != nil { - return WrapErrorISE(err, "failed unmarshalling CBOR") + if err := cbor.Unmarshal(attObj, &att); err != nil { + return WrapErrorISE(err, "error unmarshalling CBOR") } format := att.Format @@ -1506,10 +1058,14 @@ func doStepAttestationFormat(_ context.Context, prov Provisioner, ch *Challenge, // should be the ARPA address https://datatracker.ietf.org/doc/html/rfc8738#section-6. // It also references TLS Extensions [RFC6066]. func serverName(ch *Challenge) string { - if ip := net.ParseIP(ch.Value); ip != nil { - return reverseAddr(ip) + var serverName string + ip := net.ParseIP(ch.Value) + if ip != nil { + serverName = reverseAddr(ip) + } else { + serverName = ch.Value } - return ch.Value + return serverName } // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP diff --git a/vendor/github.com/smallstep/certificates/acme/db.go b/vendor/github.com/smallstep/certificates/acme/db.go index bcbed41..4cbb308 100644 --- a/vendor/github.com/smallstep/certificates/acme/db.go +++ b/vendor/github.com/smallstep/certificates/acme/db.go @@ -2,7 +2,6 @@ package acme import ( "context" - "database/sql" "github.com/pkg/errors" ) @@ -16,7 +15,7 @@ var ErrNotFound = errors.New("not found") // IsErrNotFound returns true if the error is a "not found" error. Returns false // otherwise. func IsErrNotFound(err error) bool { - return errors.Is(err, ErrNotFound) || errors.Is(err, sql.ErrNoRows) + return errors.Is(err, ErrNotFound) } // DB is the DB interface expected by the step-ca ACME API. @@ -56,19 +55,6 @@ type DB interface { UpdateOrder(ctx context.Context, o *Order) error } -// WireDB is the interface used for operations on ACME Orders for Wire identifiers. This -// is not a general purpose interface, and it should only be used when Wire identifiers -// are enabled in the CA configuration. Currently it provides a runtime assertion only; -// not at compile time. -type WireDB interface { - DB - GetAllOrdersByAccountID(ctx context.Context, accountID string) ([]string, error) - CreateDpopToken(ctx context.Context, orderID string, dpop map[string]interface{}) error - GetDpopToken(ctx context.Context, orderID string) (map[string]interface{}, error) - CreateOidcToken(ctx context.Context, orderID string, idToken map[string]interface{}) error - GetOidcToken(ctx context.Context, orderID string) (map[string]interface{}, error) -} - type dbKey struct{} // NewDatabaseContext adds the given acme database to the context. @@ -136,18 +122,6 @@ type MockDB struct { MockError error } -// MockWireDB is an implementation of the WireDB interface that should only be used as -// a mock in tests. It embeds the MockDB, as it is an extension of the existing database -// methods. -type MockWireDB struct { - MockDB - MockGetAllOrdersByAccountID func(ctx context.Context, accountID string) ([]string, error) - MockGetDpopToken func(ctx context.Context, orderID string) (map[string]interface{}, error) - MockCreateDpopToken func(ctx context.Context, orderID string, dpop map[string]interface{}) error - MockGetOidcToken func(ctx context.Context, orderID string) (map[string]interface{}, error) - MockCreateOidcToken func(ctx context.Context, orderID string, idToken map[string]interface{}) error -} - // CreateAccount mock. func (m *MockDB) CreateAccount(ctx context.Context, acc *Account) error { if m.MockCreateAccount != nil { @@ -417,49 +391,3 @@ func (m *MockDB) GetOrdersByAccountID(ctx context.Context, accID string) ([]stri } return m.MockRet1.([]string), m.MockError } - -// GetAllOrdersByAccountID returns a list of any order IDs owned by the account. -func (m *MockWireDB) GetAllOrdersByAccountID(ctx context.Context, accountID string) ([]string, error) { - if m.MockGetAllOrdersByAccountID != nil { - return m.MockGetAllOrdersByAccountID(ctx, accountID) - } else if m.MockError != nil { - return nil, m.MockError - } - return m.MockRet1.([]string), m.MockError -} - -// GetDpop retrieves a DPoP from the database. -func (m *MockWireDB) GetDpopToken(ctx context.Context, orderID string) (map[string]any, error) { - if m.MockGetDpopToken != nil { - return m.MockGetDpopToken(ctx, orderID) - } else if m.MockError != nil { - return nil, m.MockError - } - return m.MockRet1.(map[string]any), m.MockError -} - -// CreateDpop creates DPoP resources and saves them to the DB. -func (m *MockWireDB) CreateDpopToken(ctx context.Context, orderID string, dpop map[string]any) error { - if m.MockCreateDpopToken != nil { - return m.MockCreateDpopToken(ctx, orderID, dpop) - } - return m.MockError -} - -// GetOidcToken retrieves an oidc token from the database. -func (m *MockWireDB) GetOidcToken(ctx context.Context, orderID string) (map[string]any, error) { - if m.MockGetOidcToken != nil { - return m.MockGetOidcToken(ctx, orderID) - } else if m.MockError != nil { - return nil, m.MockError - } - return m.MockRet1.(map[string]any), m.MockError -} - -// CreateOidcToken creates oidc token resources and saves them to the DB. -func (m *MockWireDB) CreateOidcToken(ctx context.Context, orderID string, idToken map[string]any) error { - if m.MockCreateOidcToken != nil { - return m.MockCreateOidcToken(ctx, orderID, idToken) - } - return m.MockError -} diff --git a/vendor/github.com/smallstep/certificates/acme/db/nosql/account.go b/vendor/github.com/smallstep/certificates/acme/db/nosql/account.go index 9b03db8..d590ccb 100644 --- a/vendor/github.com/smallstep/certificates/acme/db/nosql/account.go +++ b/vendor/github.com/smallstep/certificates/acme/db/nosql/account.go @@ -18,7 +18,6 @@ type dbAccount struct { Contact []string `json:"contact,omitempty"` Status acme.Status `json:"status"` LocationPrefix string `json:"locationPrefix"` - ProvisionerID string `json:"provisionerID,omitempty"` ProvisionerName string `json:"provisionerName"` CreatedAt time.Time `json:"createdAt"` DeactivatedAt time.Time `json:"deactivatedAt"` @@ -70,7 +69,6 @@ func (db *DB) GetAccount(ctx context.Context, id string) (*acme.Account, error) Key: dbacc.Key, ID: dbacc.ID, LocationPrefix: dbacc.LocationPrefix, - ProvisionerID: dbacc.ProvisionerID, ProvisionerName: dbacc.ProvisionerName, }, nil } @@ -99,7 +97,6 @@ func (db *DB) CreateAccount(ctx context.Context, acc *acme.Account) error { Status: acc.Status, CreatedAt: clock.Now(), LocationPrefix: acc.LocationPrefix, - ProvisionerID: acc.ProvisionerID, ProvisionerName: acc.ProvisionerName, } diff --git a/vendor/github.com/smallstep/certificates/acme/db/nosql/challenge.go b/vendor/github.com/smallstep/certificates/acme/db/nosql/challenge.go index e7c9aa2..9af1ae0 100644 --- a/vendor/github.com/smallstep/certificates/acme/db/nosql/challenge.go +++ b/vendor/github.com/smallstep/certificates/acme/db/nosql/challenge.go @@ -19,7 +19,6 @@ type dbChallenge struct { Status acme.Status `json:"status"` Token string `json:"token"` Value string `json:"value"` - Target string `json:"target,omitempty"` ValidatedAt string `json:"validatedAt"` CreatedAt time.Time `json:"createdAt"` Error *acme.Error `json:"error"` // TODO(hs): a bit dangerous; should become db-specific type @@ -62,7 +61,6 @@ func (db *DB) CreateChallenge(ctx context.Context, ch *acme.Challenge) error { Token: ch.Token, CreatedAt: clock.Now(), Type: ch.Type, - Target: ch.Target, } return db.save(ctx, ch.ID, dbch, nil, "challenge", challengeTable) @@ -86,7 +84,6 @@ func (db *DB) GetChallenge(ctx context.Context, id, authzID string) (*acme.Chall Token: dbch.Token, Error: dbch.Error, ValidatedAt: dbch.ValidatedAt, - Target: dbch.Target, } return ch, nil } diff --git a/vendor/github.com/smallstep/certificates/acme/db/nosql/nosql.go b/vendor/github.com/smallstep/certificates/acme/db/nosql/nosql.go index b2921f5..d19e298 100644 --- a/vendor/github.com/smallstep/certificates/acme/db/nosql/nosql.go +++ b/vendor/github.com/smallstep/certificates/acme/db/nosql/nosql.go @@ -23,8 +23,6 @@ var ( externalAccountKeyTable = []byte("acme_external_account_keys") externalAccountKeyIDsByReferenceTable = []byte("acme_external_account_keyID_reference_index") externalAccountKeyIDsByProvisionerIDTable = []byte("acme_external_account_keyID_provisionerID_index") - wireDpopTokenTable = []byte("wire_acme_dpop_token") - wireOidcTokenTable = []byte("wire_acme_oidc_token") ) // DB is a struct that implements the AcmeDB interface. @@ -38,11 +36,11 @@ func New(db nosqlDB.DB) (*DB, error) { challengeTable, nonceTable, orderTable, ordersByAccountIDTable, certTable, certBySerialTable, externalAccountKeyTable, externalAccountKeyIDsByReferenceTable, externalAccountKeyIDsByProvisionerIDTable, - wireDpopTokenTable, wireOidcTokenTable, } for _, b := range tables { if err := db.CreateTable(b); err != nil { - return nil, errors.Wrapf(err, "error creating table %s", string(b)) + return nil, errors.Wrapf(err, "error creating table %s", + string(b)) } } return &DB{db}, nil diff --git a/vendor/github.com/smallstep/certificates/acme/db/nosql/order.go b/vendor/github.com/smallstep/certificates/acme/db/nosql/order.go index 983fbe8..fc8f211 100644 --- a/vendor/github.com/smallstep/certificates/acme/db/nosql/order.go +++ b/vendor/github.com/smallstep/certificates/acme/db/nosql/order.go @@ -98,7 +98,7 @@ func (db *DB) CreateOrder(ctx context.Context, o *acme.Order) error { return err } - _, err = db.updateAddOrderIDs(ctx, o.AccountID, false, o.ID) + _, err = db.updateAddOrderIDs(ctx, o.AccountID, o.ID) if err != nil { return err } @@ -117,11 +117,10 @@ func (db *DB) UpdateOrder(ctx context.Context, o *acme.Order) error { nu.Status = o.Status nu.Error = o.Error nu.CertificateID = o.CertificateID - return db.save(ctx, old.ID, nu, old, "order", orderTable) } -func (db *DB) updateAddOrderIDs(ctx context.Context, accID string, includeReadyOrders bool, addOids ...string) ([]string, error) { +func (db *DB) updateAddOrderIDs(ctx context.Context, accID string, addOids ...string) ([]string, error) { ordersByAccountMux.Lock() defer ordersByAccountMux.Unlock() @@ -152,8 +151,7 @@ func (db *DB) updateAddOrderIDs(ctx context.Context, accID string, includeReadyO if err = o.UpdateStatus(ctx, db); err != nil { return nil, acme.WrapErrorISE(err, "error updating order %s for account %s", oid, accID) } - - if o.Status == acme.StatusPending || (o.Status == acme.StatusReady && includeReadyOrders) { + if o.Status == acme.StatusPending { pendOids = append(pendOids, oid) } } @@ -185,10 +183,5 @@ func (db *DB) updateAddOrderIDs(ctx context.Context, accID string, includeReadyO // GetOrdersByAccountID returns a list of order IDs owned by the account. func (db *DB) GetOrdersByAccountID(ctx context.Context, accID string) ([]string, error) { - return db.updateAddOrderIDs(ctx, accID, false) -} - -// GetAllOrdersByAccountID returns a list of any order IDs owned by the account. -func (db *DB) GetAllOrdersByAccountID(ctx context.Context, accID string) ([]string, error) { - return db.updateAddOrderIDs(ctx, accID, true) + return db.updateAddOrderIDs(ctx, accID) } diff --git a/vendor/github.com/smallstep/certificates/acme/db/nosql/wire.go b/vendor/github.com/smallstep/certificates/acme/db/nosql/wire.go deleted file mode 100644 index 03b9350..0000000 --- a/vendor/github.com/smallstep/certificates/acme/db/nosql/wire.go +++ /dev/null @@ -1,121 +0,0 @@ -package nosql - -import ( - "context" - "encoding/json" - "fmt" - "time" - - "github.com/smallstep/certificates/acme" - "github.com/smallstep/nosql" -) - -type dbDpopToken struct { - ID string `json:"id"` - Content []byte `json:"content"` - CreatedAt time.Time `json:"createdAt"` -} - -// getDBDpopToken retrieves and unmarshals an DPoP type from the database. -func (db *DB) getDBDpopToken(_ context.Context, orderID string) (*dbDpopToken, error) { - b, err := db.db.Get(wireDpopTokenTable, []byte(orderID)) - if err != nil { - if nosql.IsErrNotFound(err) { - return nil, acme.NewError(acme.ErrorMalformedType, "dpop token %q not found", orderID) - } - return nil, fmt.Errorf("failed loading dpop token %q: %w", orderID, err) - } - - d := new(dbDpopToken) - if err := json.Unmarshal(b, d); err != nil { - return nil, fmt.Errorf("failed unmarshaling dpop token %q into dbDpopToken: %w", orderID, err) - } - return d, nil -} - -// GetDpopToken retrieves an DPoP from the database. -func (db *DB) GetDpopToken(ctx context.Context, orderID string) (map[string]any, error) { - dbDpop, err := db.getDBDpopToken(ctx, orderID) - if err != nil { - return nil, err - } - - dpop := make(map[string]any) - err = json.Unmarshal(dbDpop.Content, &dpop) - - return dpop, err -} - -// CreateDpopToken creates DPoP resources and saves them to the DB. -func (db *DB) CreateDpopToken(ctx context.Context, orderID string, dpop map[string]any) error { - content, err := json.Marshal(dpop) - if err != nil { - return fmt.Errorf("failed marshaling dpop token: %w", err) - } - - now := clock.Now() - dbDpop := &dbDpopToken{ - ID: orderID, - Content: content, - CreatedAt: now, - } - if err := db.save(ctx, orderID, dbDpop, nil, "dpop", wireDpopTokenTable); err != nil { - return fmt.Errorf("failed saving dpop token: %w", err) - } - return nil -} - -type dbOidcToken struct { - ID string `json:"id"` - Content []byte `json:"content"` - CreatedAt time.Time `json:"createdAt"` -} - -// getDBOidcToken retrieves and unmarshals an OIDC id token type from the database. -func (db *DB) getDBOidcToken(_ context.Context, orderID string) (*dbOidcToken, error) { - b, err := db.db.Get(wireOidcTokenTable, []byte(orderID)) - if err != nil { - if nosql.IsErrNotFound(err) { - return nil, acme.NewError(acme.ErrorMalformedType, "oidc token %q not found", orderID) - } - return nil, fmt.Errorf("failed loading oidc token %q: %w", orderID, err) - } - - o := new(dbOidcToken) - if err := json.Unmarshal(b, o); err != nil { - return nil, fmt.Errorf("failed unmarshaling oidc token %q into dbOidcToken: %w", orderID, err) - } - return o, nil -} - -// GetOidcToken retrieves an oidc token from the database. -func (db *DB) GetOidcToken(ctx context.Context, orderID string) (map[string]any, error) { - dbOidc, err := db.getDBOidcToken(ctx, orderID) - if err != nil { - return nil, err - } - - idToken := make(map[string]any) - err = json.Unmarshal(dbOidc.Content, &idToken) - - return idToken, err -} - -// CreateOidcToken creates oidc token resources and saves them to the DB. -func (db *DB) CreateOidcToken(ctx context.Context, orderID string, idToken map[string]any) error { - content, err := json.Marshal(idToken) - if err != nil { - return fmt.Errorf("failed marshaling oidc token: %w", err) - } - - now := clock.Now() - dbOidc := &dbOidcToken{ - ID: orderID, - Content: content, - CreatedAt: now, - } - if err := db.save(ctx, orderID, dbOidc, nil, "oidc", wireOidcTokenTable); err != nil { - return fmt.Errorf("failed saving oidc token: %w", err) - } - return nil -} diff --git a/vendor/github.com/smallstep/certificates/acme/errors.go b/vendor/github.com/smallstep/certificates/acme/errors.go index 3c5fdb8..658ec6e 100644 --- a/vendor/github.com/smallstep/certificates/acme/errors.go +++ b/vendor/github.com/smallstep/certificates/acme/errors.go @@ -294,14 +294,14 @@ type Subproblem struct { } // NewError creates a new Error. -func NewError(pt ProblemType, msg string, args ...any) *Error { +func NewError(pt ProblemType, msg string, args ...interface{}) *Error { return newError(pt, errors.Errorf(msg, args...)) } // NewDetailedError creates a new Error that includes the error // message in the details, providing more information to the // ACME client. -func NewDetailedError(pt ProblemType, msg string, args ...any) *Error { +func NewDetailedError(pt ProblemType, msg string, args ...interface{}) *Error { return NewError(pt, msg, args...).withDetail() } @@ -324,7 +324,7 @@ func (e *Error) AddSubproblems(subproblems ...Subproblem) *Error { // NewSubproblem creates a new Subproblem. The msg and args // are used to create a new error, which is set as the Detail, allowing // for more detailed error messages to be returned to the ACME client. -func NewSubproblem(pt ProblemType, msg string, args ...any) Subproblem { +func NewSubproblem(pt ProblemType, msg string, args ...interface{}) Subproblem { e := newError(pt, fmt.Errorf(msg, args...)) s := Subproblem{ Type: e.Type, @@ -335,7 +335,7 @@ func NewSubproblem(pt ProblemType, msg string, args ...any) Subproblem { // NewSubproblemWithIdentifier creates a new Subproblem with a specific ACME // Identifier. It calls NewSubproblem and sets the Identifier. -func NewSubproblemWithIdentifier(pt ProblemType, identifier Identifier, msg string, args ...any) Subproblem { +func NewSubproblemWithIdentifier(pt ProblemType, identifier Identifier, msg string, args ...interface{}) Subproblem { s := NewSubproblem(pt, msg, args...) s.Identifier = &identifier return s @@ -362,12 +362,12 @@ func newError(pt ProblemType, err error) *Error { } // NewErrorISE creates a new ErrorServerInternalType Error. -func NewErrorISE(msg string, args ...any) *Error { +func NewErrorISE(msg string, args ...interface{}) *Error { return NewError(ErrorServerInternalType, msg, args...) } // WrapError attempts to wrap the internal error. -func WrapError(typ ProblemType, err error, msg string, args ...any) *Error { +func WrapError(typ ProblemType, err error, msg string, args ...interface{}) *Error { var e *Error switch { case err == nil: @@ -384,12 +384,12 @@ func WrapError(typ ProblemType, err error, msg string, args ...any) *Error { } } -func WrapDetailedError(typ ProblemType, err error, msg string, args ...any) *Error { +func WrapDetailedError(typ ProblemType, err error, msg string, args ...interface{}) *Error { return WrapError(typ, err, msg, args...).withDetail() } // WrapErrorISE shortcut to wrap an internal server error type. -func WrapErrorISE(err error, msg string, args ...any) *Error { +func WrapErrorISE(err error, msg string, args ...interface{}) *Error { return WrapError(ErrorServerInternalType, err, msg, args...) } @@ -415,7 +415,7 @@ func (e *Error) Cause() error { } // ToLog implements the EnableLogger interface. -func (e *Error) ToLog() (any, error) { +func (e *Error) ToLog() (interface{}, error) { b, err := json.Marshal(e) if err != nil { return nil, WrapErrorISE(err, "error marshaling acme.Error for logging") @@ -424,7 +424,7 @@ func (e *Error) ToLog() (any, error) { } // Render implements render.RenderableError for Error. -func (e *Error) Render(w http.ResponseWriter, r *http.Request) { +func (e *Error) Render(w http.ResponseWriter) { w.Header().Set("Content-Type", "application/problem+json") - render.JSONStatus(w, r, e, e.StatusCode()) + render.JSONStatus(w, e, e.StatusCode()) } diff --git a/vendor/github.com/smallstep/certificates/acme/linker.go b/vendor/github.com/smallstep/certificates/acme/linker.go index 18997c5..d142bf1 100644 --- a/vendor/github.com/smallstep/certificates/acme/linker.go +++ b/vendor/github.com/smallstep/certificates/acme/linker.go @@ -186,19 +186,19 @@ func (l *linker) Middleware(next http.Handler) http.Handler { nameEscaped := chi.URLParam(r, "provisionerID") name, err := url.PathUnescape(nameEscaped) if err != nil { - render.Error(w, r, WrapErrorISE(err, "error url unescaping provisioner name '%s'", nameEscaped)) + render.Error(w, WrapErrorISE(err, "error url unescaping provisioner name '%s'", nameEscaped)) return } p, err := authority.MustFromContext(ctx).LoadProvisionerByName(name) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } acmeProv, ok := p.(*provisioner.ACME) if !ok { - render.Error(w, r, NewError(ErrorAccountDoesNotExistType, "provisioner must be of type ACME")) + render.Error(w, NewError(ErrorAccountDoesNotExistType, "provisioner must be of type ACME")) return } diff --git a/vendor/github.com/smallstep/certificates/acme/order.go b/vendor/github.com/smallstep/certificates/acme/order.go index c23befd..13c16b2 100644 --- a/vendor/github.com/smallstep/certificates/acme/order.go +++ b/vendor/github.com/smallstep/certificates/acme/order.go @@ -5,22 +5,15 @@ import ( "context" "crypto/subtle" "crypto/x509" - "encoding/asn1" "encoding/json" - "errors" - "fmt" "net" - "net/url" "sort" "strings" "time" + "github.com/smallstep/certificates/authority/provisioner" "go.step.sm/crypto/keyutil" "go.step.sm/crypto/x509util" - - "github.com/smallstep/certificates/acme/wire" - "github.com/smallstep/certificates/authority/provisioner" - "github.com/smallstep/certificates/webhook" ) type IdentifierType string @@ -33,10 +26,6 @@ const ( // PermanentIdentifier is the ACME permanent-identifier identifier type // defined in https://datatracker.ietf.org/doc/html/draft-bweeks-acme-device-attest-00 PermanentIdentifier IdentifierType = "permanent-identifier" - // WireUser is the Wire user identifier type - WireUser IdentifierType = "wireapp-user" - // WireDevice is the Wire device identifier type - WireDevice IdentifierType = "wireapp-device" ) // Identifier encodes the type that an order pertains to. @@ -132,11 +121,9 @@ func (o *Order) UpdateStatus(ctx context.Context, db DB) error { default: return NewErrorISE("unrecognized order status: %s", o.Status) } - if err := db.UpdateOrder(ctx, o); err != nil { return WrapErrorISE(err, "error updating order") } - return nil } @@ -209,32 +196,7 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques // Template data data := x509util.NewTemplateData() - if o.containsWireIdentifiers() { - wireDB, ok := db.(WireDB) - if !ok { - return fmt.Errorf("db %T is not a WireDB", db) - } - subject, err := createWireSubject(o, csr) - if err != nil { - return fmt.Errorf("failed creating Wire subject: %w", err) - } - data.SetSubject(subject) - - // Inject Wire's custom challenges into the template once they have been validated - dpop, err := wireDB.GetDpopToken(ctx, o.ID) - if err != nil { - return fmt.Errorf("failed getting Wire DPoP token: %w", err) - } - data.Set("Dpop", dpop) - - oidc, err := wireDB.GetOidcToken(ctx, o.ID) - if err != nil { - return fmt.Errorf("failed getting Wire OIDC token: %w", err) - } - data.Set("Oidc", oidc) - } else { - data.SetCommonName(csr.Subject.CommonName) - } + data.SetCommonName(csr.Subject.CommonName) // Custom sign options passed to authority.Sign var extraOptions []provisioner.SignOption @@ -306,18 +268,6 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques NotAfter: provisioner.NewTimeDuration(o.NotAfter), }, signOps...) if err != nil { - // Add subproblem for webhook errors, others can be added later. - var webhookErr *webhook.Error - if errors.As(err, &webhookErr) { - //nolint:govet // ignore non-constant format string - acmeError := NewDetailedError(ErrorUnauthorizedType, webhookErr.Error()) - acmeError.AddSubproblems(Subproblem{ - Type: fmt.Sprintf("urn:smallstep:acme:error:%s", webhookErr.Code), - Detail: webhookErr.Message, - }) - return acmeError - } - return WrapErrorISE(err, "error signing certificate for order %s", o.ID) } @@ -333,76 +283,15 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques o.CertificateID = cert.ID o.Status = StatusValid - if err = db.UpdateOrder(ctx, o); err != nil { return WrapErrorISE(err, "error updating order %s", o.ID) } - return nil } -// containsWireIdentifiers checks if [Order] contains ACME -// identifiers for the WireUser or WireDevice types. -func (o *Order) containsWireIdentifiers() bool { - for _, i := range o.Identifiers { - if i.Type == WireUser || i.Type == WireDevice { - return true - } - } - return false -} - -// createWireSubject creates the subject for an [Order] with WireUser identifiers. -func createWireSubject(o *Order, csr *x509.CertificateRequest) (subject x509util.Subject, err error) { - wireUserIDs, wireDeviceIDs, otherIDs := 0, 0, 0 - for _, identifier := range o.Identifiers { - switch identifier.Type { - case WireUser: - wireID, err := wire.ParseUserID(identifier.Value) - if err != nil { - return subject, NewErrorISE("unmarshal wireID: %s", err) - } - - // TODO: temporarily using a custom OIDC for carrying the display name without having it listed as a DNS SAN. - // reusing LDAP's OID for diplay name see http://oid-info.com/get/2.16.840.1.113730.3.1.241 - displayNameOid := asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 3, 1, 241} - var foundDisplayName = false - for _, entry := range csr.Subject.Names { - if entry.Type.Equal(displayNameOid) { - foundDisplayName = true - displayName := entry.Value.(string) - if displayName != wireID.Name { - return subject, NewErrorISE("expected displayName %v, found %v", wireID.Name, displayName) - } - } - } - if !foundDisplayName { - return subject, NewErrorISE("CSR must contain the display name in '2.16.840.1.113730.3.1.241' OID") - } - - if len(csr.Subject.Organization) == 0 || !strings.EqualFold(csr.Subject.Organization[0], wireID.Domain) { - return subject, NewErrorISE("expected Organization [%s], found %v", wireID.Domain, csr.Subject.Organization) - } - subject.CommonName = wireID.Name - subject.Organization = []string{wireID.Domain} - wireUserIDs++ - case WireDevice: - wireDeviceIDs++ - default: - otherIDs++ - } - } - - if otherIDs > 0 || wireUserIDs != 1 && wireDeviceIDs != 1 { - return subject, NewErrorISE("order must have exactly one WireUser and WireDevice identifier") - } - - return -} - func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativeName, error) { var sans []x509util.SubjectAlternativeName - if len(csr.EmailAddresses) > 0 { + if len(csr.EmailAddresses) > 0 || len(csr.URIs) > 0 { return sans, NewError(ErrorBadCSRType, "Only DNS names and IP addresses are allowed") } @@ -410,8 +299,7 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ orderNames := make([]string, numberOfIdentifierType(DNS, o.Identifiers)) orderIPs := make([]net.IP, numberOfIdentifierType(IP, o.Identifiers)) orderPIDs := make([]string, numberOfIdentifierType(PermanentIdentifier, o.Identifiers)) - tmpOrderURIs := make([]*url.URL, numberOfIdentifierType(WireUser, o.Identifiers)+numberOfIdentifierType(WireDevice, o.Identifiers)) - indexDNS, indexIP, indexPID, indexURI := 0, 0, 0, 0 + indexDNS, indexIP, indexPID := 0, 0, 0 for _, n := range o.Identifiers { switch n.Type { case DNS: @@ -423,37 +311,14 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ case PermanentIdentifier: orderPIDs[indexPID] = n.Value indexPID++ - case WireUser: - wireID, err := wire.ParseUserID(n.Value) - if err != nil { - return sans, NewErrorISE("unsupported identifier value in order: %s", n.Value) - } - handle, err := url.Parse(wireID.Handle) - if err != nil { - return sans, NewErrorISE("handle must be a URI: %s", wireID.Handle) - } - tmpOrderURIs[indexURI] = handle - indexURI++ - case WireDevice: - wireID, err := wire.ParseDeviceID(n.Value) - if err != nil { - return sans, NewErrorISE("unsupported identifier value in order: %s", n.Value) - } - clientID, err := url.Parse(wireID.ClientID) - if err != nil { - return sans, NewErrorISE("clientId must be a URI: %s", wireID.ClientID) - } - tmpOrderURIs[indexURI] = clientID - indexURI++ default: return sans, NewErrorISE("unsupported identifier type in order: %s", n.Type) } } orderNames = uniqueSortedLowerNames(orderNames) orderIPs = uniqueSortedIPs(orderIPs) - orderURIs := uniqueSortedURIStrings(tmpOrderURIs) - totalNumberOfSANs := len(csr.DNSNames) + len(csr.IPAddresses) + len(csr.URIs) + totalNumberOfSANs := len(csr.DNSNames) + len(csr.IPAddresses) sans = make([]x509util.SubjectAlternativeName, totalNumberOfSANs) index := 0 @@ -496,26 +361,6 @@ func (o *Order) sans(csr *x509.CertificateRequest) ([]x509util.SubjectAlternativ index++ } - if len(csr.URIs) != len(tmpOrderURIs) { - return sans, NewError(ErrorBadCSRType, "CSR URIs do not match identifiers exactly: "+ - "CSR URIs = %v, Order URIs = %v", csr.URIs, tmpOrderURIs) - } - - // sort URI list - csrURIs := uniqueSortedURIStrings(csr.URIs) - - for i := range csrURIs { - if csrURIs[i] != orderURIs[i] { - return sans, NewError(ErrorBadCSRType, "CSR URIs do not match identifiers exactly: "+ - "CSR URIs = %v, Order URIs = %v", csr.URIs, tmpOrderURIs) - } - sans[index] = x509util.SubjectAlternativeName{ - Type: x509util.URIType, - Value: orderURIs[i], - } - index++ - } - return sans, nil } @@ -585,21 +430,6 @@ func uniqueSortedLowerNames(names []string) (unique []string) { } unique = make([]string, 0, len(nameMap)) for name := range nameMap { - if name != "" { - unique = append(unique, name) - } - } - sort.Strings(unique) - return -} - -func uniqueSortedURIStrings(uris []*url.URL) (unique []string) { - uriMap := make(map[string]struct{}, len(uris)) - for _, name := range uris { - uriMap[name.String()] = struct{}{} - } - unique = make([]string, 0, len(uriMap)) - for name := range uriMap { unique = append(unique, name) } sort.Strings(unique) diff --git a/vendor/github.com/smallstep/certificates/acme/wire/id.go b/vendor/github.com/smallstep/certificates/acme/wire/id.go deleted file mode 100644 index 5b77f08..0000000 --- a/vendor/github.com/smallstep/certificates/acme/wire/id.go +++ /dev/null @@ -1,91 +0,0 @@ -package wire - -import ( - "encoding/json" - "errors" - "fmt" - "net/url" - "strings" -) - -type UserID struct { - Name string `json:"name,omitempty"` - Domain string `json:"domain,omitempty"` - Handle string `json:"handle,omitempty"` -} - -type DeviceID struct { - Name string `json:"name,omitempty"` - Domain string `json:"domain,omitempty"` - ClientID string `json:"client-id,omitempty"` - Handle string `json:"handle,omitempty"` -} - -func ParseUserID(value string) (id UserID, err error) { - if err = json.Unmarshal([]byte(value), &id); err != nil { - return - } - - switch { - case id.Handle == "": - err = errors.New("handle must not be empty") - case id.Name == "": - err = errors.New("name must not be empty") - case id.Domain == "": - err = errors.New("domain must not be empty") - } - - return -} - -func ParseDeviceID(value string) (id DeviceID, err error) { - if err = json.Unmarshal([]byte(value), &id); err != nil { - return - } - - switch { - case id.Handle == "": - err = errors.New("handle must not be empty") - case id.Name == "": - err = errors.New("name must not be empty") - case id.Domain == "": - err = errors.New("domain must not be empty") - case id.ClientID == "": - err = errors.New("client-id must not be empty") - } - - return -} - -type ClientID struct { - Scheme string - Username string - DeviceID string - Domain string -} - -// ParseClientID parses a Wire clientID. The ClientID format is as follows: -// -// "wireapp://CzbfFjDOQrenCbDxVmgnFw!594930e9d50bb175@wire.com", -// -// where '!' is used as a separator between the user id & device id. -func ParseClientID(clientID string) (ClientID, error) { - clientIDURI, err := url.Parse(clientID) - if err != nil { - return ClientID{}, fmt.Errorf("invalid Wire client ID URI %q: %w", clientID, err) - } - if clientIDURI.Scheme != "wireapp" { - return ClientID{}, fmt.Errorf("invalid Wire client ID scheme %q; expected \"wireapp\"", clientIDURI.Scheme) - } - fullUsername := clientIDURI.User.Username() - parts := strings.SplitN(fullUsername, "!", 2) - if len(parts) != 2 { - return ClientID{}, fmt.Errorf("invalid Wire client ID username %q", fullUsername) - } - return ClientID{ - Scheme: clientIDURI.Scheme, - Username: parts[0], - DeviceID: parts[1], - Domain: clientIDURI.Host, - }, nil -} diff --git a/vendor/github.com/smallstep/certificates/api/api.go b/vendor/github.com/smallstep/certificates/api/api.go index fa55449..6916983 100644 --- a/vendor/github.com/smallstep/certificates/api/api.go +++ b/vendor/github.com/smallstep/certificates/api/api.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "crypto" - "crypto/dsa" // support legacy algorithms + "crypto/dsa" //nolint:staticcheck // support legacy algorithms "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" @@ -52,7 +52,6 @@ type Authority interface { Revoke(context.Context, *authority.RevokeOptions) error GetEncryptedKey(kid string) (string, error) GetRoots() ([]*x509.Certificate, error) - GetIntermediateCertificates() []*x509.Certificate GetFederation() ([]*x509.Certificate, error) Version() authority.Version GetCertificateRevocationList() (*authority.CertificateRevocationListInfo, error) @@ -296,11 +295,6 @@ type RootsResponse struct { Certificates []Certificate `json:"crts"` } -// IntermediatesResponse is the response object of the intermediates request. -type IntermediatesResponse struct { - Certificates []Certificate `json:"crts"` -} - // FederationResponse is the response object of the federation request. type FederationResponse struct { Certificates []Certificate `json:"crts"` @@ -336,10 +330,7 @@ func Route(r Router) { r.MethodFunc("GET", "/provisioners/{kid}/encrypted-key", ProvisionerKey) r.MethodFunc("GET", "/roots", Roots) r.MethodFunc("GET", "/roots.pem", RootsPEM) - r.MethodFunc("GET", "/intermediates", Intermediates) - r.MethodFunc("GET", "/intermediates.pem", IntermediatesPEM) r.MethodFunc("GET", "/federation", Federation) - // SSH CA r.MethodFunc("POST", "/ssh/sign", SSHSign) r.MethodFunc("POST", "/ssh/renew", SSHRenew) @@ -362,15 +353,15 @@ func Route(r Router) { // Version is an HTTP handler that returns the version of the server. func Version(w http.ResponseWriter, r *http.Request) { v := mustAuthority(r.Context()).Version() - render.JSON(w, r, VersionResponse{ + render.JSON(w, VersionResponse{ Version: v.Version, RequireClientAuthentication: v.RequireClientAuthentication, }) } // Health is an HTTP handler that returns the status of the server. -func Health(w http.ResponseWriter, r *http.Request) { - render.JSON(w, r, HealthResponse{Status: "ok"}) +func Health(w http.ResponseWriter, _ *http.Request) { + render.JSON(w, HealthResponse{Status: "ok"}) } // Root is an HTTP handler that using the SHA256 from the URL, returns the root @@ -381,11 +372,11 @@ func Root(w http.ResponseWriter, r *http.Request) { // Load root certificate with the cert, err := mustAuthority(r.Context()).Root(sum) if err != nil { - render.Error(w, r, errs.Wrapf(http.StatusNotFound, err, "%s was not found", r.RequestURI)) + render.Error(w, errs.Wrapf(http.StatusNotFound, err, "%s was not found", r.RequestURI)) return } - render.JSON(w, r, &RootResponse{RootPEM: Certificate{cert}}) + render.JSON(w, &RootResponse{RootPEM: Certificate{cert}}) } func certChainToPEM(certChain []*x509.Certificate) []Certificate { @@ -400,17 +391,17 @@ func certChainToPEM(certChain []*x509.Certificate) []Certificate { func Provisioners(w http.ResponseWriter, r *http.Request) { cursor, limit, err := ParseCursor(r) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } p, next, err := mustAuthority(r.Context()).GetProvisioners(cursor, limit) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } - render.JSON(w, r, &ProvisionersResponse{ + render.JSON(w, &ProvisionersResponse{ Provisioners: p, NextCursor: next, }) @@ -421,18 +412,18 @@ func ProvisionerKey(w http.ResponseWriter, r *http.Request) { kid := chi.URLParam(r, "kid") key, err := mustAuthority(r.Context()).GetEncryptedKey(kid) if err != nil { - render.Error(w, r, errs.NotFoundErr(err)) + render.Error(w, errs.NotFoundErr(err)) return } - render.JSON(w, r, &ProvisionerKeyResponse{key}) + render.JSON(w, &ProvisionerKeyResponse{key}) } // Roots returns all the root certificates for the CA. func Roots(w http.ResponseWriter, r *http.Request) { roots, err := mustAuthority(r.Context()).GetRoots() if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error getting roots")) + render.Error(w, errs.ForbiddenErr(err, "error getting roots")) return } @@ -441,7 +432,7 @@ func Roots(w http.ResponseWriter, r *http.Request) { certs[i] = Certificate{roots[i]} } - render.JSONStatus(w, r, &RootsResponse{ + render.JSONStatus(w, &RootsResponse{ Certificates: certs, }, http.StatusCreated) } @@ -450,7 +441,7 @@ func Roots(w http.ResponseWriter, r *http.Request) { func RootsPEM(w http.ResponseWriter, r *http.Request) { roots, err := mustAuthority(r.Context()).GetRoots() if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } @@ -463,48 +454,7 @@ func RootsPEM(w http.ResponseWriter, r *http.Request) { }) if _, err := w.Write(block); err != nil { - log.Error(w, r, err) - return - } - } -} - -// Intermediates returns all the intermediate certificates of the CA. -func Intermediates(w http.ResponseWriter, r *http.Request) { - intermediates := mustAuthority(r.Context()).GetIntermediateCertificates() - if len(intermediates) == 0 { - render.Error(w, r, errs.NotImplemented("error getting intermediates: method not implemented")) - return - } - - certs := make([]Certificate, len(intermediates)) - for i := range intermediates { - certs[i] = Certificate{intermediates[i]} - } - - render.JSONStatus(w, r, &IntermediatesResponse{ - Certificates: certs, - }, http.StatusCreated) -} - -// IntermediatesPEM returns all the intermediate certificates for the CA in PEM format. -func IntermediatesPEM(w http.ResponseWriter, r *http.Request) { - intermediates := mustAuthority(r.Context()).GetIntermediateCertificates() - if len(intermediates) == 0 { - render.Error(w, r, errs.NotImplemented("error getting intermediates: method not implemented")) - return - } - - w.Header().Set("Content-Type", "application/x-pem-file") - - for _, crt := range intermediates { - block := pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: crt.Raw, - }) - - if _, err := w.Write(block); err != nil { - log.Error(w, r, err) + log.Error(w, err) return } } @@ -514,7 +464,7 @@ func IntermediatesPEM(w http.ResponseWriter, r *http.Request) { func Federation(w http.ResponseWriter, r *http.Request) { federated, err := mustAuthority(r.Context()).GetFederation() if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error getting federated roots")) + render.Error(w, errs.ForbiddenErr(err, "error getting federated roots")) return } @@ -523,7 +473,7 @@ func Federation(w http.ResponseWriter, r *http.Request) { certs[i] = Certificate{federated[i]} } - render.JSONStatus(w, r, &FederationResponse{ + render.JSONStatus(w, &FederationResponse{ Certificates: certs, }, http.StatusCreated) } diff --git a/vendor/github.com/smallstep/certificates/api/crl.go b/vendor/github.com/smallstep/certificates/api/crl.go index 92e1481..c10d08c 100644 --- a/vendor/github.com/smallstep/certificates/api/crl.go +++ b/vendor/github.com/smallstep/certificates/api/crl.go @@ -13,12 +13,12 @@ import ( func CRL(w http.ResponseWriter, r *http.Request) { crlInfo, err := mustAuthority(r.Context()).GetCertificateRevocationList() if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } if crlInfo == nil { - render.Error(w, r, errs.New(http.StatusNotFound, "no CRL available")) + render.Error(w, errs.New(http.StatusNotFound, "no CRL available")) return } diff --git a/vendor/github.com/smallstep/certificates/api/log/log.go b/vendor/github.com/smallstep/certificates/api/log/log.go index 6cc61a7..687d61c 100644 --- a/vendor/github.com/smallstep/certificates/api/log/log.go +++ b/vendor/github.com/smallstep/certificates/api/log/log.go @@ -2,7 +2,6 @@ package log import ( - "context" "fmt" "net/http" "os" @@ -10,29 +9,6 @@ import ( "github.com/pkg/errors" ) -type errorLoggerKey struct{} - -// ErrorLogger is the function type used to log errors. -type ErrorLogger func(http.ResponseWriter, *http.Request, error) - -func (fn ErrorLogger) call(w http.ResponseWriter, r *http.Request, err error) { - if fn == nil { - return - } - fn(w, r, err) -} - -// WithErrorLogger returns a new context with the given error logger. -func WithErrorLogger(ctx context.Context, fn ErrorLogger) context.Context { - return context.WithValue(ctx, errorLoggerKey{}, fn) -} - -// ErrorLoggerFromContext returns an error logger from the context. -func ErrorLoggerFromContext(ctx context.Context) (fn ErrorLogger) { - fn, _ = ctx.Value(errorLoggerKey{}).(ErrorLogger) - return -} - // StackTracedError is the set of errors implementing the StackTrace function. // // Errors implementing this interface have their stack traces logged when passed @@ -51,10 +27,8 @@ type fieldCarrier interface { // Error adds to the response writer the given error if it implements // logging.ResponseLogger. If it does not implement it, then writes the error // using the log package. -func Error(w http.ResponseWriter, r *http.Request, err error) { - ErrorLoggerFromContext(r.Context()).call(w, r, err) - - fc, ok := w.(fieldCarrier) +func Error(rw http.ResponseWriter, err error) { + fc, ok := rw.(fieldCarrier) if !ok { return } @@ -77,7 +51,7 @@ func Error(w http.ResponseWriter, r *http.Request, err error) { // EnabledResponse log the response object if it implements the EnableLogger // interface. -func EnabledResponse(rw http.ResponseWriter, r *http.Request, v any) { +func EnabledResponse(rw http.ResponseWriter, v any) { type enableLogger interface { ToLog() (any, error) } @@ -85,7 +59,7 @@ func EnabledResponse(rw http.ResponseWriter, r *http.Request, v any) { if el, ok := v.(enableLogger); ok { out, err := el.ToLog() if err != nil { - Error(rw, r, err) + Error(rw, err) return } diff --git a/vendor/github.com/smallstep/certificates/api/read/read.go b/vendor/github.com/smallstep/certificates/api/read/read.go index 6f75c41..72530b8 100644 --- a/vendor/github.com/smallstep/certificates/api/read/read.go +++ b/vendor/github.com/smallstep/certificates/api/read/read.go @@ -51,7 +51,7 @@ func (e badProtoJSONError) Error() string { } // Render implements render.RenderableError for badProtoJSONError -func (e badProtoJSONError) Render(w http.ResponseWriter, r *http.Request) { +func (e badProtoJSONError) Render(w http.ResponseWriter) { v := struct { Type string `json:"type"` Detail string `json:"detail"` @@ -62,5 +62,5 @@ func (e badProtoJSONError) Render(w http.ResponseWriter, r *http.Request) { // trim the proto prefix for the message Message: strings.TrimSpace(strings.TrimPrefix(e.Error(), "proto:")), } - render.JSONStatus(w, r, v, http.StatusBadRequest) + render.JSONStatus(w, v, http.StatusBadRequest) } diff --git a/vendor/github.com/smallstep/certificates/api/rekey.go b/vendor/github.com/smallstep/certificates/api/rekey.go index 772de21..cda843a 100644 --- a/vendor/github.com/smallstep/certificates/api/rekey.go +++ b/vendor/github.com/smallstep/certificates/api/rekey.go @@ -29,25 +29,25 @@ func (s *RekeyRequest) Validate() error { // Rekey is similar to renew except that the certificate will be renewed with new key from csr. func Rekey(w http.ResponseWriter, r *http.Request) { if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 { - render.Error(w, r, errs.BadRequest("missing client certificate")) + render.Error(w, errs.BadRequest("missing client certificate")) return } var body RekeyRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } a := mustAuthority(r.Context()) certChain, err := a.Rekey(r.TLS.PeerCertificates[0], body.CsrPEM.CertificateRequest.PublicKey) if err != nil { - render.Error(w, r, errs.Wrap(http.StatusInternalServerError, err, "cahandler.Rekey")) + render.Error(w, errs.Wrap(http.StatusInternalServerError, err, "cahandler.Rekey")) return } certChainPEM := certChainToPEM(certChain) @@ -57,7 +57,7 @@ func Rekey(w http.ResponseWriter, r *http.Request) { } LogCertificate(w, certChain[0]) - render.JSONStatus(w, r, &SignResponse{ + render.JSONStatus(w, &SignResponse{ ServerPEM: certChainPEM[0], CaPEM: caPEM, CertChainPEM: certChainPEM, diff --git a/vendor/github.com/smallstep/certificates/api/render/render.go b/vendor/github.com/smallstep/certificates/api/render/render.go index 1c66280..7829ba2 100644 --- a/vendor/github.com/smallstep/certificates/api/render/render.go +++ b/vendor/github.com/smallstep/certificates/api/render/render.go @@ -13,8 +13,8 @@ import ( ) // JSON is shorthand for JSONStatus(w, v, http.StatusOK). -func JSON(w http.ResponseWriter, r *http.Request, v interface{}) { - JSONStatus(w, r, v, http.StatusOK) +func JSON(w http.ResponseWriter, v interface{}) { + JSONStatus(w, v, http.StatusOK) } // JSONStatus marshals v into w. It additionally sets the status code of @@ -22,7 +22,7 @@ func JSON(w http.ResponseWriter, r *http.Request, v interface{}) { // // JSONStatus sets the Content-Type of w to application/json unless one is // specified. -func JSONStatus(w http.ResponseWriter, r *http.Request, v interface{}, status int) { +func JSONStatus(w http.ResponseWriter, v interface{}, status int) { setContentTypeUnlessPresent(w, "application/json") w.WriteHeader(status) @@ -43,7 +43,7 @@ func JSONStatus(w http.ResponseWriter, r *http.Request, v interface{}, status in } } - log.EnabledResponse(w, r, v) + log.EnabledResponse(w, v) } // ProtoJSON is shorthand for ProtoJSONStatus(w, m, http.StatusOK). @@ -80,22 +80,22 @@ func setContentTypeUnlessPresent(w http.ResponseWriter, contentType string) { type RenderableError interface { error - Render(http.ResponseWriter, *http.Request) + Render(http.ResponseWriter) } // Error marshals the JSON representation of err to w. In case err implements // RenderableError its own Render method will be called instead. -func Error(rw http.ResponseWriter, r *http.Request, err error) { - log.Error(rw, r, err) +func Error(w http.ResponseWriter, err error) { + log.Error(w, err) - var re RenderableError - if errors.As(err, &re) { - re.Render(rw, r) + var r RenderableError + if errors.As(err, &r) { + r.Render(w) return } - JSONStatus(rw, r, err, statusCodeFromError(err)) + JSONStatus(w, err, statusCodeFromError(err)) } // StatusCodedError is the set of errors that implement the basic StatusCode diff --git a/vendor/github.com/smallstep/certificates/api/renew.go b/vendor/github.com/smallstep/certificates/api/renew.go index 7cd3707..1b9ed95 100644 --- a/vendor/github.com/smallstep/certificates/api/renew.go +++ b/vendor/github.com/smallstep/certificates/api/renew.go @@ -23,20 +23,19 @@ func Renew(w http.ResponseWriter, r *http.Request) { // Get the leaf certificate from the peer or the token. cert, token, err := getPeerCertificate(r) if err != nil { - render.Error(w, r, err) + render.Error(w, err) return } // The token can be used by RAs to renew a certificate. if token != "" { ctx = authority.NewTokenContext(ctx, token) - logOtt(w, token) } a := mustAuthority(ctx) certChain, err := a.RenewContext(ctx, cert, nil) if err != nil { - render.Error(w, r, errs.Wrap(http.StatusInternalServerError, err, "cahandler.Renew")) + render.Error(w, errs.Wrap(http.StatusInternalServerError, err, "cahandler.Renew")) return } certChainPEM := certChainToPEM(certChain) @@ -46,7 +45,7 @@ func Renew(w http.ResponseWriter, r *http.Request) { } LogCertificate(w, certChain[0]) - render.JSONStatus(w, r, &SignResponse{ + render.JSONStatus(w, &SignResponse{ ServerPEM: certChainPEM[0], CaPEM: caPEM, CertChainPEM: certChainPEM, diff --git a/vendor/github.com/smallstep/certificates/api/revoke.go b/vendor/github.com/smallstep/certificates/api/revoke.go index 41969c0..dc639d5 100644 --- a/vendor/github.com/smallstep/certificates/api/revoke.go +++ b/vendor/github.com/smallstep/certificates/api/revoke.go @@ -57,12 +57,12 @@ func (r *RevokeRequest) Validate() (err error) { func Revoke(w http.ResponseWriter, r *http.Request) { var body RevokeRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -81,7 +81,7 @@ func Revoke(w http.ResponseWriter, r *http.Request) { if body.OTT != "" { logOtt(w, body.OTT) if _, err := a.Authorize(ctx, body.OTT); err != nil { - render.Error(w, r, errs.UnauthorizedErr(err)) + render.Error(w, errs.UnauthorizedErr(err)) return } opts.OTT = body.OTT @@ -90,12 +90,12 @@ func Revoke(w http.ResponseWriter, r *http.Request) { // the client certificate Serial Number must match the serial number // being revoked. if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 { - render.Error(w, r, errs.BadRequest("missing ott or client certificate")) + render.Error(w, errs.BadRequest("missing ott or client certificate")) return } opts.Crt = r.TLS.PeerCertificates[0] if opts.Crt.SerialNumber.String() != opts.Serial { - render.Error(w, r, errs.BadRequest("serial number in client certificate different than body")) + render.Error(w, errs.BadRequest("serial number in client certificate different than body")) return } // TODO: should probably be checking if the certificate was revoked here. @@ -106,12 +106,12 @@ func Revoke(w http.ResponseWriter, r *http.Request) { } if err := a.Revoke(ctx, opts); err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error revoking certificate")) + render.Error(w, errs.ForbiddenErr(err, "error revoking certificate")) return } logRevoke(w, opts) - render.JSON(w, r, &RevokeResponse{Status: "ok"}) + render.JSON(w, &RevokeResponse{Status: "ok"}) } func logRevoke(w http.ResponseWriter, ri *authority.RevokeOptions) { diff --git a/vendor/github.com/smallstep/certificates/api/sign.go b/vendor/github.com/smallstep/certificates/api/sign.go index bff4176..26b3c39 100644 --- a/vendor/github.com/smallstep/certificates/api/sign.go +++ b/vendor/github.com/smallstep/certificates/api/sign.go @@ -52,13 +52,13 @@ type SignResponse struct { func Sign(w http.ResponseWriter, r *http.Request) { var body SignRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } logOtt(w, body.OTT) if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -74,13 +74,13 @@ func Sign(w http.ResponseWriter, r *http.Request) { ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod) signOpts, err := a.Authorize(ctx, body.OTT) if err != nil { - render.Error(w, r, errs.UnauthorizedErr(err)) + render.Error(w, errs.UnauthorizedErr(err)) return } certChain, err := a.SignWithContext(ctx, body.CsrPEM.CertificateRequest, opts, signOpts...) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error signing certificate")) + render.Error(w, errs.ForbiddenErr(err, "error signing certificate")) return } certChainPEM := certChainToPEM(certChain) @@ -90,7 +90,7 @@ func Sign(w http.ResponseWriter, r *http.Request) { } LogCertificate(w, certChain[0]) - render.JSONStatus(w, r, &SignResponse{ + render.JSONStatus(w, &SignResponse{ ServerPEM: certChainPEM[0], CaPEM: caPEM, CertChainPEM: certChainPEM, diff --git a/vendor/github.com/smallstep/certificates/api/ssh.go b/vendor/github.com/smallstep/certificates/api/ssh.go index e1024f3..08294c7 100644 --- a/vendor/github.com/smallstep/certificates/api/ssh.go +++ b/vendor/github.com/smallstep/certificates/api/ssh.go @@ -6,11 +6,8 @@ import ( "encoding/base64" "encoding/json" "net/http" - "net/url" - "strings" "time" - "github.com/google/uuid" "github.com/pkg/errors" "golang.org/x/crypto/ssh" @@ -256,19 +253,19 @@ type SSHBastionResponse struct { func SSHSign(w http.ResponseWriter, r *http.Request) { var body SSHSignRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } logOtt(w, body.OTT) if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } publicKey, err := ssh.ParsePublicKey(body.PublicKey) if err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error parsing publicKey")) + render.Error(w, errs.BadRequestErr(err, "error parsing publicKey")) return } @@ -276,7 +273,7 @@ func SSHSign(w http.ResponseWriter, r *http.Request) { if body.AddUserPublicKey != nil { addUserPublicKey, err = ssh.ParsePublicKey(body.AddUserPublicKey) if err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error parsing addUserPublicKey")) + render.Error(w, errs.BadRequestErr(err, "error parsing addUserPublicKey")) return } } @@ -292,18 +289,17 @@ func SSHSign(w http.ResponseWriter, r *http.Request) { ctx := provisioner.NewContextWithMethod(r.Context(), provisioner.SSHSignMethod) ctx = provisioner.NewContextWithToken(ctx, body.OTT) - ctx = provisioner.NewContextWithCertType(ctx, opts.CertType) a := mustAuthority(ctx) signOpts, err := a.Authorize(ctx, body.OTT) if err != nil { - render.Error(w, r, errs.UnauthorizedErr(err)) + render.Error(w, errs.UnauthorizedErr(err)) return } cert, err := a.SignSSH(ctx, publicKey, opts, signOpts...) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error signing ssh certificate")) + render.Error(w, errs.ForbiddenErr(err, "error signing ssh certificate")) return } @@ -311,7 +307,7 @@ func SSHSign(w http.ResponseWriter, r *http.Request) { if addUserPublicKey != nil && authority.IsValidForAddUser(cert) == nil { addUserCert, err := a.SignSSHAddUser(ctx, addUserPublicKey, cert) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error signing ssh certificate")) + render.Error(w, errs.ForbiddenErr(err, "error signing ssh certificate")) return } addUserCertificate = &SSHCertificate{addUserCert} @@ -324,27 +320,26 @@ func SSHSign(w http.ResponseWriter, r *http.Request) { ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignIdentityMethod) signOpts, err := a.Authorize(ctx, body.OTT) if err != nil { - render.Error(w, r, errs.UnauthorizedErr(err)) + render.Error(w, errs.UnauthorizedErr(err)) return } // Enforce the same duration as ssh certificate. signOpts = append(signOpts, &identityModifier{ - Identity: getIdentityURI(cr), NotBefore: time.Unix(int64(cert.ValidAfter), 0), NotAfter: time.Unix(int64(cert.ValidBefore), 0), }) certChain, err := a.SignWithContext(ctx, cr, provisioner.SignOptions{}, signOpts...) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error signing identity certificate")) + render.Error(w, errs.ForbiddenErr(err, "error signing identity certificate")) return } identityCertificate = certChainToPEM(certChain) } LogSSHCertificate(w, cert) - render.JSONStatus(w, r, &SSHSignResponse{ + render.JSONStatus(w, &SSHSignResponse{ Certificate: SSHCertificate{cert}, AddUserCertificate: addUserCertificate, IdentityCertificate: identityCertificate, @@ -357,12 +352,12 @@ func SSHRoots(w http.ResponseWriter, r *http.Request) { ctx := r.Context() keys, err := mustAuthority(ctx).GetSSHRoots(ctx) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } if len(keys.HostKeys) == 0 && len(keys.UserKeys) == 0 { - render.Error(w, r, errs.NotFound("no keys found")) + render.Error(w, errs.NotFound("no keys found")) return } @@ -374,7 +369,7 @@ func SSHRoots(w http.ResponseWriter, r *http.Request) { resp.UserKeys = append(resp.UserKeys, SSHPublicKey{PublicKey: k}) } - render.JSON(w, r, resp) + render.JSON(w, resp) } // SSHFederation is an HTTP handler that returns the federated SSH public keys @@ -383,12 +378,12 @@ func SSHFederation(w http.ResponseWriter, r *http.Request) { ctx := r.Context() keys, err := mustAuthority(ctx).GetSSHFederation(ctx) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } if len(keys.HostKeys) == 0 && len(keys.UserKeys) == 0 { - render.Error(w, r, errs.NotFound("no keys found")) + render.Error(w, errs.NotFound("no keys found")) return } @@ -400,7 +395,7 @@ func SSHFederation(w http.ResponseWriter, r *http.Request) { resp.UserKeys = append(resp.UserKeys, SSHPublicKey{PublicKey: k}) } - render.JSON(w, r, resp) + render.JSON(w, resp) } // SSHConfig is an HTTP handler that returns rendered templates for ssh clients @@ -408,18 +403,18 @@ func SSHFederation(w http.ResponseWriter, r *http.Request) { func SSHConfig(w http.ResponseWriter, r *http.Request) { var body SSHConfigRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } ctx := r.Context() ts, err := mustAuthority(ctx).GetSSHConfig(ctx, body.Type, body.Data) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } @@ -430,32 +425,32 @@ func SSHConfig(w http.ResponseWriter, r *http.Request) { case provisioner.SSHHostCert: cfg.HostTemplates = ts default: - render.Error(w, r, errs.InternalServer("it should hot get here")) + render.Error(w, errs.InternalServer("it should hot get here")) return } - render.JSON(w, r, cfg) + render.JSON(w, cfg) } // SSHCheckHost is the HTTP handler that returns if a hosts certificate exists or not. func SSHCheckHost(w http.ResponseWriter, r *http.Request) { var body SSHCheckPrincipalRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } ctx := r.Context() exists, err := mustAuthority(ctx).CheckSSHHost(ctx, body.Principal, body.Token) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } - render.JSON(w, r, &SSHCheckPrincipalResponse{ + render.JSON(w, &SSHCheckPrincipalResponse{ Exists: exists, }) } @@ -470,10 +465,10 @@ func SSHGetHosts(w http.ResponseWriter, r *http.Request) { ctx := r.Context() hosts, err := mustAuthority(ctx).GetSSHHosts(ctx, cert) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } - render.JSON(w, r, &SSHGetHostsResponse{ + render.JSON(w, &SSHGetHostsResponse{ Hosts: hosts, }) } @@ -482,63 +477,35 @@ func SSHGetHosts(w http.ResponseWriter, r *http.Request) { func SSHBastion(w http.ResponseWriter, r *http.Request) { var body SSHBastionRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } ctx := r.Context() bastion, err := mustAuthority(ctx).GetSSHBastion(ctx, body.User, body.Hostname) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } - render.JSON(w, r, &SSHBastionResponse{ + render.JSON(w, &SSHBastionResponse{ Hostname: body.Hostname, Bastion: bastion, }) } -// identityModifier is a custom modifier used to force a fixed duration, and set -// the identity URI. +// identityModifier is a custom modifier used to force a fixed duration. type identityModifier struct { - Identity *url.URL NotBefore time.Time NotAfter time.Time } -// Enforce implements the enforcer interface and sets the validity bounds and -// the identity uri to the certificate. func (m *identityModifier) Enforce(cert *x509.Certificate) error { cert.NotBefore = m.NotBefore cert.NotAfter = m.NotAfter - if m.Identity != nil { - var identityURL = m.Identity.String() - for _, u := range cert.URIs { - if u.String() == identityURL { - return nil - } - } - cert.URIs = append(cert.URIs, m.Identity) - } - - return nil -} - -// getIdentityURI returns the first valid UUID URN from the given CSR. -func getIdentityURI(cr *x509.CertificateRequest) *url.URL { - for _, u := range cr.URIs { - s := u.String() - // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - if len(s) == 9+36 && strings.EqualFold(s[:9], "urn:uuid:") { - if _, err := uuid.Parse(s); err == nil { - return u - } - } - } return nil } diff --git a/vendor/github.com/smallstep/certificates/api/sshRekey.go b/vendor/github.com/smallstep/certificates/api/sshRekey.go index 0db4d4d..80fc6d8 100644 --- a/vendor/github.com/smallstep/certificates/api/sshRekey.go +++ b/vendor/github.com/smallstep/certificates/api/sshRekey.go @@ -42,19 +42,19 @@ type SSHRekeyResponse struct { func SSHRekey(w http.ResponseWriter, r *http.Request) { var body SSHRekeyRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } logOtt(w, body.OTT) if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } publicKey, err := ssh.ParsePublicKey(body.PublicKey) if err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error parsing publicKey")) + render.Error(w, errs.BadRequestErr(err, "error parsing publicKey")) return } @@ -64,18 +64,18 @@ func SSHRekey(w http.ResponseWriter, r *http.Request) { a := mustAuthority(ctx) signOpts, err := a.Authorize(ctx, body.OTT) if err != nil { - render.Error(w, r, errs.UnauthorizedErr(err)) + render.Error(w, errs.UnauthorizedErr(err)) return } oldCert, _, err := provisioner.ExtractSSHPOPCert(body.OTT) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } newCert, err := a.RekeySSH(ctx, oldCert, publicKey, signOpts...) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error rekeying ssh certificate")) + render.Error(w, errs.ForbiddenErr(err, "error rekeying ssh certificate")) return } @@ -85,12 +85,12 @@ func SSHRekey(w http.ResponseWriter, r *http.Request) { identity, err := renewIdentityCertificate(r, notBefore, notAfter) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error renewing identity certificate")) + render.Error(w, errs.ForbiddenErr(err, "error renewing identity certificate")) return } LogSSHCertificate(w, newCert) - render.JSONStatus(w, r, &SSHRekeyResponse{ + render.JSONStatus(w, &SSHRekeyResponse{ Certificate: SSHCertificate{newCert}, IdentityCertificate: identity, }, http.StatusCreated) diff --git a/vendor/github.com/smallstep/certificates/api/sshRenew.go b/vendor/github.com/smallstep/certificates/api/sshRenew.go index dea7cea..cd6d9bd 100644 --- a/vendor/github.com/smallstep/certificates/api/sshRenew.go +++ b/vendor/github.com/smallstep/certificates/api/sshRenew.go @@ -40,13 +40,13 @@ type SSHRenewResponse struct { func SSHRenew(w http.ResponseWriter, r *http.Request) { var body SSHRenewRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } logOtt(w, body.OTT) if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -56,18 +56,18 @@ func SSHRenew(w http.ResponseWriter, r *http.Request) { a := mustAuthority(ctx) _, err := a.Authorize(ctx, body.OTT) if err != nil { - render.Error(w, r, errs.UnauthorizedErr(err)) + render.Error(w, errs.UnauthorizedErr(err)) return } oldCert, _, err := provisioner.ExtractSSHPOPCert(body.OTT) if err != nil { - render.Error(w, r, errs.InternalServerErr(err)) + render.Error(w, errs.InternalServerErr(err)) return } newCert, err := a.RenewSSH(ctx, oldCert) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error renewing ssh certificate")) + render.Error(w, errs.ForbiddenErr(err, "error renewing ssh certificate")) return } @@ -77,12 +77,12 @@ func SSHRenew(w http.ResponseWriter, r *http.Request) { identity, err := renewIdentityCertificate(r, notBefore, notAfter) if err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error renewing identity certificate")) + render.Error(w, errs.ForbiddenErr(err, "error renewing identity certificate")) return } LogSSHCertificate(w, newCert) - render.JSONStatus(w, r, &SSHSignResponse{ + render.JSONStatus(w, &SSHSignResponse{ Certificate: SSHCertificate{newCert}, IdentityCertificate: identity, }, http.StatusCreated) diff --git a/vendor/github.com/smallstep/certificates/api/sshRevoke.go b/vendor/github.com/smallstep/certificates/api/sshRevoke.go index 2fe4919..d377def 100644 --- a/vendor/github.com/smallstep/certificates/api/sshRevoke.go +++ b/vendor/github.com/smallstep/certificates/api/sshRevoke.go @@ -51,12 +51,12 @@ func (r *SSHRevokeRequest) Validate() (err error) { func SSHRevoke(w http.ResponseWriter, r *http.Request) { var body SSHRevokeRequest if err := read.JSON(r.Body, &body); err != nil { - render.Error(w, r, errs.BadRequestErr(err, "error reading request body")) + render.Error(w, errs.BadRequestErr(err, "error reading request body")) return } if err := body.Validate(); err != nil { - render.Error(w, r, err) + render.Error(w, err) return } @@ -75,18 +75,18 @@ func SSHRevoke(w http.ResponseWriter, r *http.Request) { logOtt(w, body.OTT) if _, err := a.Authorize(ctx, body.OTT); err != nil { - render.Error(w, r, errs.UnauthorizedErr(err)) + render.Error(w, errs.UnauthorizedErr(err)) return } opts.OTT = body.OTT if err := a.Revoke(ctx, opts); err != nil { - render.Error(w, r, errs.ForbiddenErr(err, "error revoking ssh certificate")) + render.Error(w, errs.ForbiddenErr(err, "error revoking ssh certificate")) return } logSSHRevoke(w, opts) - render.JSON(w, r, &SSHRevokeResponse{Status: "ok"}) + render.JSON(w, &SSHRevokeResponse{Status: "ok"}) } func logSSHRevoke(w http.ResponseWriter, ri *authority.RevokeOptions) { diff --git a/vendor/github.com/smallstep/certificates/authority/admin/errors.go b/vendor/github.com/smallstep/certificates/authority/admin/errors.go index a14e2de..c729c8b 100644 --- a/vendor/github.com/smallstep/certificates/authority/admin/errors.go +++ b/vendor/github.com/smallstep/certificates/authority/admin/errors.go @@ -205,8 +205,8 @@ func (e *Error) ToLog() (interface{}, error) { } // Render implements render.RenderableError for Error. -func (e *Error) Render(w http.ResponseWriter, r *http.Request) { +func (e *Error) Render(w http.ResponseWriter) { e.Message = e.Err.Error() - render.JSONStatus(w, r, e, e.StatusCode()) + render.JSONStatus(w, e, e.StatusCode()) } diff --git a/vendor/github.com/smallstep/certificates/authority/authority.go b/vendor/github.com/smallstep/certificates/authority/authority.go index 4a91236..d3b9328 100644 --- a/vendor/github.com/smallstep/certificates/authority/authority.go +++ b/vendor/github.com/smallstep/certificates/authority/authority.go @@ -49,7 +49,6 @@ type Authority struct { templates *templates.Templates linkedCAToken string webhookClient *http.Client - httpClient *http.Client // X509 CA password []byte @@ -257,10 +256,7 @@ func (a *Authority) ReloadAdminResources(ctx context.Context) error { provClxn := provisioner.NewCollection(provisionerConfig.Audiences) for _, p := range provList { if err := p.Init(provisionerConfig); err != nil { - log.Printf("failed to initialize %s provisioner %q: %v\n", p.GetType(), p.GetName(), err) - p = provisioner.Uninitialized{ - Interface: p, Reason: err, - } + return err } if err := provClxn.Store(p); err != nil { return err @@ -492,15 +488,6 @@ func (a *Authority) init() error { a.certificates.Store(hex.EncodeToString(sum[:]), crt) } - // Initialize HTTPClient with all root certs - clientRoots := make([]*x509.Certificate, 0, len(a.rootX509Certs)+len(a.federatedX509Certs)) - clientRoots = append(clientRoots, a.rootX509Certs...) - clientRoots = append(clientRoots, a.federatedX509Certs...) - a.httpClient, err = newHTTPClient(clientRoots...) - if err != nil { - return err - } - // Decrypt and load SSH keys var tmplVars templates.Step if a.config.SSH != nil { diff --git a/vendor/github.com/smallstep/certificates/authority/authorize.go b/vendor/github.com/smallstep/certificates/authority/authorize.go index 0a693c6..0214768 100644 --- a/vendor/github.com/smallstep/certificates/authority/authorize.go +++ b/vendor/github.com/smallstep/certificates/authority/authorize.go @@ -64,10 +64,6 @@ func (a *Authority) getProvisionerFromToken(token string) (provisioner.Interface if !ok { return nil, nil, fmt.Errorf("provisioner not found or invalid audience (%s)", strings.Join(claims.Audience, ", ")) } - // If the provisioner is disabled, send an appropriate message to the client - if _, ok := p.(provisioner.Uninitialized); ok { - return nil, nil, errs.New(http.StatusUnauthorized, "provisioner %q is disabled due to an initialization error", p.GetName()) - } return p, &claims, nil } diff --git a/vendor/github.com/smallstep/certificates/authority/export.go b/vendor/github.com/smallstep/certificates/authority/export.go index 43479d5..b8efbbd 100644 --- a/vendor/github.com/smallstep/certificates/authority/export.go +++ b/vendor/github.com/smallstep/certificates/authority/export.go @@ -8,12 +8,10 @@ import ( "strings" "github.com/pkg/errors" - "google.golang.org/protobuf/types/known/structpb" - - "github.com/smallstep/cli-utils/step" - "go.step.sm/linkedca" - "github.com/smallstep/certificates/authority/provisioner" + "go.step.sm/cli-utils/step" + "go.step.sm/linkedca" + "google.golang.org/protobuf/types/known/structpb" ) // Export creates a linkedca configuration form the current ca.json and loaded diff --git a/vendor/github.com/smallstep/certificates/authority/http_client.go b/vendor/github.com/smallstep/certificates/authority/http_client.go deleted file mode 100644 index ff61e45..0000000 --- a/vendor/github.com/smallstep/certificates/authority/http_client.go +++ /dev/null @@ -1,34 +0,0 @@ -package authority - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "net/http" -) - -// newHTTPClient will return an HTTP client that trusts the system cert pool and -// the given roots, but only if the http.DefaultTransport is an *http.Transport. -// If not, it will return the default HTTP client. -func newHTTPClient(roots ...*x509.Certificate) (*http.Client, error) { - if tr, ok := http.DefaultTransport.(*http.Transport); ok { - pool, err := x509.SystemCertPool() - if err != nil { - return nil, fmt.Errorf("error initializing http client: %w", err) - } - for _, crt := range roots { - pool.AddCert(crt) - } - - tr = tr.Clone() - tr.TLSClientConfig = &tls.Config{ - MinVersion: tls.VersionTLS12, - RootCAs: pool, - } - return &http.Client{ - Transport: tr, - }, nil - } - - return &http.Client{}, nil -} diff --git a/vendor/github.com/smallstep/certificates/authority/linkedca.go b/vendor/github.com/smallstep/certificates/authority/linkedca.go index aa8de3a..3eaa76c 100644 --- a/vendor/github.com/smallstep/certificates/authority/linkedca.go +++ b/vendor/github.com/smallstep/certificates/authority/linkedca.go @@ -110,7 +110,7 @@ func newLinkedCAClient(token string) (*linkedCaClient, error) { tlsConfig.GetClientCertificate = renewer.GetClientCertificate // Start mTLS client - conn, err := grpc.NewClient(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) + conn, err := grpc.Dial(u.Host, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) if err != nil { return nil, errors.Wrapf(err, "error connecting %s", u.Host) } @@ -478,7 +478,10 @@ func getAuthority(sans []string) (string, error) { // getRootCertificate creates an insecure majordomo client and returns the // verified root certificate. func getRootCertificate(endpoint, fingerprint string) (*x509.Certificate, error) { - conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + conn, err := grpc.DialContext(ctx, endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ //nolint:gosec // used in bootstrap protocol InsecureSkipVerify: true, // lgtm[go/disabled-certificate-check] }))) @@ -486,7 +489,7 @@ func getRootCertificate(endpoint, fingerprint string) (*x509.Certificate, error) return nil, errors.Wrapf(err, "error connecting %s", endpoint) } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) defer cancel() client := linkedca.NewMajordomoClient(conn) @@ -528,7 +531,11 @@ func getRootCertificate(endpoint, fingerprint string) (*x509.Certificate, error) // login creates a new majordomo client with just the root ca pool and returns // the signed certificate and tls configuration. func login(authority, token string, csr *x509.CertificateRequest, signer crypto.PrivateKey, endpoint string, rootCAs *x509.CertPool) (*tls.Certificate, *tls.Config, error) { - conn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + // Connect to majordomo + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + conn, err := grpc.DialContext(ctx, endpoint, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ MinVersion: tls.VersionTLS12, RootCAs: rootCAs, }))) @@ -537,7 +544,7 @@ func login(authority, token string, csr *x509.CertificateRequest, signer crypto. } // Login to get the signed certificate - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) defer cancel() client := linkedca.NewMajordomoClient(conn) diff --git a/vendor/github.com/smallstep/certificates/authority/policy/engine.go b/vendor/github.com/smallstep/certificates/authority/policy/engine.go index 475522d..d3881d9 100644 --- a/vendor/github.com/smallstep/certificates/authority/policy/engine.go +++ b/vendor/github.com/smallstep/certificates/authority/policy/engine.go @@ -91,7 +91,7 @@ func (e *Engine) IsSSHCertificateAllowed(cert *ssh.Certificate) error { // when no host policy engine is configured, but a user policy engine is // configured, the host certificate is denied. if e.sshHostPolicy == nil && e.sshUserPolicy != nil { - return errors.New("authority not allowed to sign SSH host certificates when SSH user certificate policy is active") + return errors.New("authority not allowed to sign ssh host certificates") } // return result of SSH host policy evaluation @@ -100,12 +100,12 @@ func (e *Engine) IsSSHCertificateAllowed(cert *ssh.Certificate) error { // when no user policy engine is configured, but a host policy engine is // configured, the user certificate is denied. if e.sshUserPolicy == nil && e.sshHostPolicy != nil { - return errors.New("authority not allowed to sign SSH user certificates when SSH host certificate policy is active") + return errors.New("authority not allowed to sign ssh user certificates") } // return result of SSH user policy evaluation return e.sshUserPolicy.IsSSHCertificateAllowed(cert) default: - return fmt.Errorf("unexpected SSH certificate type %q", cert.CertType) + return fmt.Errorf("unexpected ssh certificate type %q", cert.CertType) } } diff --git a/vendor/github.com/smallstep/certificates/authority/policy/policy.go b/vendor/github.com/smallstep/certificates/authority/policy/policy.go index 1da45e8..96c7d7e 100644 --- a/vendor/github.com/smallstep/certificates/authority/policy/policy.go +++ b/vendor/github.com/smallstep/certificates/authority/policy/policy.go @@ -21,7 +21,6 @@ type HostPolicy policy.SSHNamePolicyEngine func NewX509PolicyEngine(policyOptions X509PolicyOptionsInterface) (X509Policy, error) { // return early if no policy engine options to configure if policyOptions == nil { - //nolint:nilnil,nolintlint // expected values return nil, nil } @@ -51,7 +50,6 @@ func NewX509PolicyEngine(policyOptions X509PolicyOptionsInterface) (X509Policy, // ensure no policy engine is returned when no name options were provided if len(options) == 0 { - //nolint:nilnil,nolintlint // expected values return nil, nil } @@ -95,7 +93,6 @@ func NewSSHHostPolicyEngine(policyOptions SSHPolicyOptionsInterface) (HostPolicy func newSSHPolicyEngine(policyOptions SSHPolicyOptionsInterface, typ sshPolicyEngineType) (policy.SSHNamePolicyEngine, error) { // return early if no policy engine options to configure if policyOptions == nil { - //nolint:nilnil,nolintlint // expected values return nil, nil } @@ -137,7 +134,6 @@ func newSSHPolicyEngine(policyOptions SSHPolicyOptionsInterface, typ sshPolicyEn // ensure no policy engine is returned when no name options were provided if len(options) == 0 { - //nolint:nilnil,nolintlint // expected values return nil, nil } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/acme.go b/vendor/github.com/smallstep/certificates/authority/provisioner/acme.go index 3b7fa65..96f37d5 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/acme.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/acme.go @@ -10,7 +10,6 @@ import ( "time" "github.com/pkg/errors" - "github.com/smallstep/certificates/acme/wire" "go.step.sm/linkedca" ) @@ -27,10 +26,6 @@ const ( TLS_ALPN_01 ACMEChallenge = "tls-alpn-01" // DEVICE_ATTEST_01 is the device-attest-01 ACME challenge. DEVICE_ATTEST_01 ACMEChallenge = "device-attest-01" - // WIREOIDC_01 is the Wire OIDC challenge. - WIREOIDC_01 ACMEChallenge = "wire-oidc-01" - // WIREDPOP_01 is the Wire DPoP challenge. - WIREDPOP_01 ACMEChallenge = "wire-dpop-01" ) // String returns a normalized version of the challenge. @@ -41,7 +36,7 @@ func (c ACMEChallenge) String() string { // Validate returns an error if the acme challenge is not a valid one. func (c ACMEChallenge) Validate() error { switch ACMEChallenge(c.String()) { - case HTTP_01, DNS_01, TLS_ALPN_01, DEVICE_ATTEST_01, WIREOIDC_01, WIREDPOP_01: + case HTTP_01, DNS_01, TLS_ALPN_01, DEVICE_ATTEST_01: return nil default: return fmt.Errorf("acme challenge %q is not supported", c) @@ -107,8 +102,7 @@ type ACME struct { RequireEAB bool `json:"requireEAB,omitempty"` // Challenges contains the enabled challenges for this provisioner. If this // value is not set the default http-01, dns-01 and tls-alpn-01 challenges - // will be enabled, device-attest-01, wire-oidc-01 and wire-dpop-01 will be - // disabled. + // will be enabled, device-attest-01 will be disabled. Challenges []ACMEChallenge `json:"challenges,omitempty"` // AttestationFormats contains the enabled attestation formats for this // provisioner. If this value is not set the default apple, step and tpm @@ -212,50 +206,10 @@ func (p *ACME) Init(config Config) (err error) { } } - if err := p.initializeWireOptions(); err != nil { - return fmt.Errorf("failed initializing Wire options: %w", err) - } - p.ctl, err = NewController(p, p.Claims, config, p.Options) return } -// initializeWireOptions initializes the options for the ACME Wire -// integration. It'll return early if no Wire challenge types are -// enabled. -func (p *ACME) initializeWireOptions() error { - hasWireChallenges := false - for _, c := range p.Challenges { - if c == WIREOIDC_01 || c == WIREDPOP_01 { - hasWireChallenges = true - break - } - } - if !hasWireChallenges { - return nil - } - - w, err := p.GetOptions().GetWireOptions() - if err != nil { - return fmt.Errorf("failed getting Wire options: %w", err) - } - - if err := w.Validate(); err != nil { - return fmt.Errorf("failed validating Wire options: %w", err) - } - - // at this point the Wire options have been validated, and (mostly) - // initialized. Remote keys will be loaded upon the first verification, - // currently. - // TODO(hs): can/should we "prime" the underlying remote keyset, to verify - // auto discovery works as expected? Because of the current way provisioners - // are initialized, doing that as part of the initialization isn't the best - // time to do it, because it could result in operations not resulting in the - // expected result in all cases. - - return nil -} - // ACMEIdentifierType encodes ACME Identifier types type ACMEIdentifierType string @@ -264,10 +218,6 @@ const ( IP ACMEIdentifierType = "ip" // DNS is the ACME dns identifier type DNS ACMEIdentifierType = "dns" - // WireUser is the Wire user identifier type - WireUser ACMEIdentifierType = "wireapp-user" - // WireDevice is the Wire device identifier type - WireDevice ACMEIdentifierType = "wireapp-device" ) // ACMEIdentifier encodes ACME Order Identifiers @@ -293,18 +243,6 @@ func (p *ACME) AuthorizeOrderIdentifier(_ context.Context, identifier ACMEIdenti err = x509Policy.IsIPAllowed(net.ParseIP(identifier.Value)) case DNS: err = x509Policy.IsDNSAllowed(identifier.Value) - case WireUser: - var wireID wire.UserID - if wireID, err = wire.ParseUserID(identifier.Value); err != nil { - return fmt.Errorf("failed parsing Wire SANs: %w", err) - } - err = x509Policy.AreSANsAllowed([]string{wireID.Handle}) - case WireDevice: - var wireID wire.DeviceID - if wireID, err = wire.ParseDeviceID(identifier.Value); err != nil { - return fmt.Errorf("failed parsing Wire SANs: %w", err) - } - err = x509Policy.AreSANsAllowed([]string{wireID.ClientID}) default: err = fmt.Errorf("invalid ACME identifier type '%s' provided", identifier.Type) } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/aws.go b/vendor/github.com/smallstep/certificates/authority/provisioner/aws.go index 9e1d9b7..e95feed 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/aws.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/aws.go @@ -358,7 +358,7 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er if p.DisableCustomSANs { dnsName := fmt.Sprintf("ip-%s.%s.compute.internal", strings.ReplaceAll(doc.PrivateIP, ".", "-"), doc.Region) so = append(so, - dnsNamesSubsetValidator([]string{dnsName}), + dnsNamesValidator([]string{dnsName}), ipAddressesValidator([]net.IP{ net.ParseIP(doc.PrivateIP), }), diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/aws_certificates.pem b/vendor/github.com/smallstep/certificates/authority/provisioner/aws_certificates.pem index 167007f..994758b 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/aws_certificates.pem +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/aws_certificates.pem @@ -1,89 +1,25 @@ # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/verify-signature.html # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/regions-certs.html use RSA format - -# certificate for us-east-2 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUVJTc+hOU+8Gk3JlqsX438Dk5c58wDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE3MTE0OVoXDTI5MDQyODE3MTE0OVowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUVJTc+hOU -+8Gk3JlqsX438Dk5c58wEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQAywJQaVNWJqW0R0T0xVOSoN1GLk9x9kKEuN67RN9CLin4dA97qa7Mr5W4P -FZ6vnh5CjOhQBRXV9xJUeYSdqVItNAUFK/fEzDdjf1nUfPlQ3OJ49u6CV01NoJ9m -usvY9kWcV46dqn2bk2MyfTTgvmeqP8fiMRPxxnVRkSzlldP5Fg== ------END CERTIFICATE----- - -# certificate for us-east-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUE1y2NIKCU+Rg4uu4u32koG9QEYIwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE3MzQwMVoXDTI5MDQyODE3MzQwMVowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUE1y2NIKC -U+Rg4uu4u32koG9QEYIwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQAlxSmwcWnhT4uAeSinJuz+1BTcKhVSWb5jT8pYjQb8ZoZkXXRGb09mvYeU -NeqOBr27rvRAnaQ/9LUQf72+SahDFuS4CMI8nwowytqbmwquqFr4dxA/SDADyRiF -ea1UoMuNHTY49J/1vPomqsVn7mugTp+TbjqCfOJTpu0temHcFA== ------END CERTIFICATE----- - -# certificate for us-west-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUK2zmY9PUSTR7rc1k2OwPYu4+g7wwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE3MDI0M1oXDTI5MDQyODE3MDI0M1owXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUK2zmY9PU -STR7rc1k2OwPYu4+g7wwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQA1Ng4QmN4n7iPh5CnadSOc0ZfM7by0dBePwZJyGvOHdaw6P6E/vEk76KsC -Q8p+akuzVzVPkU4kBK/TRqLp19wEWoVwhhTaxHjQ1tTRHqXIVlrkw4JrtFbeNM21 -GlkSLonuzmNZdivn9WuQYeGe7nUD4w3q9GgiF3CPorJe+UxtbA== ------END CERTIFICATE----- - -# certificate for us-west-2 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUFx8PxCkbHwpD31bOyCtyz3GclbgwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE3MjM1OVoXDTI5MDQyODE3MjM1OVowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUFx8PxCkb -HwpD31bOyCtyz3GclbgwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQBzOl+9Xy1+UsbUBI95HO9mbbdnuX+aMJXgG9uFZNjgNEbMcvx+h8P9IMko -z7PzFdheQQ1NLjsHH9mSR1SyC4m9ja6BsejH5nLBWyCdjfdP3muZM4O5+r7vUa1O -dWU+hP/T7DUrPAIVMOE7mpYa+WPWJrN6BlRwQkKQ7twm9kDalA== +# default certificate for "other regions" +-----BEGIN CERTIFICATE----- +MIIDIjCCAougAwIBAgIJAKnL4UEDMN/FMA0GCSqGSIb3DQEBBQUAMGoxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdTZWF0dGxlMRgw +FgYDVQQKEw9BbWF6b24uY29tIEluYy4xGjAYBgNVBAMTEWVjMi5hbWF6b25hd3Mu +Y29tMB4XDTE0MDYwNTE0MjgwMloXDTI0MDYwNTE0MjgwMlowajELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxGDAWBgNV +BAoTD0FtYXpvbi5jb20gSW5jLjEaMBgGA1UEAxMRZWMyLmFtYXpvbmF3cy5jb20w +gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIe9GN//SRK2knbjySG0ho3yqQM3 +e2TDhWO8D2e8+XZqck754gFSo99AbT2RmXClambI7xsYHZFapbELC4H91ycihvrD +jbST1ZjkLQgga0NE1q43eS68ZeTDccScXQSNivSlzJZS8HJZjgqzBlXjZftjtdJL +XeE4hwvo0sD4f3j9AgMBAAGjgc8wgcwwHQYDVR0OBBYEFCXWzAgVyrbwnFncFFIs +77VBdlE4MIGcBgNVHSMEgZQwgZGAFCXWzAgVyrbwnFncFFIs77VBdlE4oW6kbDBq +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2Vh +dHRsZTEYMBYGA1UEChMPQW1hem9uLmNvbSBJbmMuMRowGAYDVQQDExFlYzIuYW1h +em9uYXdzLmNvbYIJAKnL4UEDMN/FMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF +BQADgYEAFYcz1OgEhQBXIwIdsgCOS8vEtiJYF+j9uO6jz7VOmJqO+pRlAbRlvY8T +C1haGgSI/A1uZUKs/Zfnph0oEI0/hu1IIJ/SKBDtN5lvmZ/IzbOPIJWirlsllQIQ +7zvWbGd9c9+Rm3p04oTvhup99la7kZqevJK0QRdD/6NpCKsqP/0= -----END CERTIFICATE----- # certificate for eu-south-1 @@ -157,7 +93,7 @@ NTpxxcXmUKquX+pHmIkK1LKDO8rNE84jqxrxRsfDi6by82fjVYf2pgjJW8R1FAw+ mL5WQRFexbfB5aXhcMo0AA== -----END CERTIFICATE----- -# certificate for cn-north-1 +# certificate for cn-north-1, cn-northwest-1 -----BEGIN CERTIFICATE----- MIIDCzCCAnSgAwIBAgIJALSOMbOoU2svMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 @@ -178,48 +114,6 @@ oADS0ph+YUz5P/bUCm61wFjlxaTfwKcuTR3ytj7bFLoW5Bm7Sa+TCl3lOGb2taon SUDlRyNy1jJFstEZjOhs -----END CERTIFICATE----- -# certificate for cn-northwest-1 ------BEGIN CERTIFICATE----- -MIIDCzCCAnSgAwIBAgIJALSOMbOoU2svMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV -BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 -dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0yMzA3MDQw -ODM1MzlaFw0yODA3MDIwODM1MzlaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBX -YXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6 -b24gV2ViIFNlcnZpY2VzIExMQzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -uhhUNlqAZdcWWB/OSDVDGk3OA99EFzOn/mJlmciQ/Xwu2dFJWmSCqEAE6gjufCjQ -q3voxAhC2CF+elKtJW/C0Sz/LYo60PUqd6iXF4h+upB9HkOOGuWHXsHBTsvgkgGA -1CGgel4U0Cdq+23eANr8N8m28UzljjSnTlrYCHtzN4sCAwEAAaOB1DCB0TALBgNV -HQ8EBAMCB4AwHQYDVR0OBBYEFBkZu3wT27NnYgrfH+xJz4HJaNJoMIGOBgNVHSME -gYYwgYOAFBkZu3wT27NnYgrfH+xJz4HJaNJooWCkXjBcMQswCQYDVQQGEwJVUzEZ -MBcGA1UECBMQV2FzaGluZ3RvbiBTdGF0ZTEQMA4GA1UEBxMHU2VhdHRsZTEgMB4G -A1UEChMXQW1hem9uIFdlYiBTZXJ2aWNlcyBMTEOCCQC0jjGzqFNrLzASBgNVHRMB -Af8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4GBAECji43p+oPkYqmzll7e8Hgb -oADS0ph+YUz5P/bUCm61wFjlxaTfwKcuTR3ytj7bFLoW5Bm7Sa+TCl3lOGb2taon -2h+9NirRK6JYk87LMNvbS40HGPFumJL2NzEsGUeK+MRiWu+Oh5/lJGii3qw4YByx -SUDlRyNy1jJFstEZjOhs ------END CERTIFICATE----- - -# certificate for eu-central-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUFD5GsmkxRuecttwsCG763m3u63UwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE1NTUyOVoXDTI5MDQyODE1NTUyOVowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUFD5Gsmkx -RuecttwsCG763m3u63UwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQBBh0WaXlBsW56Hqk588MmJxsOrvcKfDjF57RgEDgnGnQaJcStCVWDO9UYO -JX2tdsPw+E7AjDqjsuxYaotLn3Mr3mK0sNOXq9BljBnWD4pARg89KZnZI8FN35HQ -O/LYOVHCknuPL123VmVRNs51qQA9hkPjvw21UzpDLxaUxt9Z/w== ------END CERTIFICATE----- - # certificate for eu-central-2 -----BEGIN CERTIFICATE----- MIICMzCCAZygAwIBAgIGAXjSGFGiMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT @@ -236,27 +130,6 @@ NBElvPCDKFvTJl4QQhToy056llO5GvdS9RK+H8xrP2mrqngApoKTApv93vHBixgF Sn5KrczRO0YSm3OjkqbydU7DFlmkXXR7GYE+5jbHvQHYiT1J5sMu -----END CERTIFICATE----- -# certificate for ap-south-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUDLA+x6tTAP3LRTr0z6nOxfsozdMwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE0MTMwMVoXDTI5MDQyODE0MTMwMVowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUDLA+x6tT -AP3LRTr0z6nOxfsozdMwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQAZ7rYKoAwwiiH1M5GJbrT/BEk3OO2VrEPw8ZxgpqQ/EKlzMlOs/0Cyrmp7 -UYyUgYFQe5nq37Z94rOUSeMgv/WRxaMwrLlLqD78cuF9DSkXaZIX/kECtVaUnjk8 -BZx0QhoIHOpQocJUSlm/dLeMuE0+0A3HNR6JVktGsUdv9ulmKw== ------END CERTIFICATE----- - # certificate for ap-south-2 -----BEGIN CERTIFICATE----- MIICMzCCAZygAwIBAgIGAXjwLj9CMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT @@ -273,48 +146,6 @@ ETwUZ9mTq2vxlV0KvuetCDNS5u4cJsxe/TGGbYP0yP2qfMl0cCImzRI5W0gn8gog dervfeT7nH5ih0TWEy/QDWfkQ601L4erm4yh4YQq8vcqAPSkf04N -----END CERTIFICATE----- -# certificate for ap-southeast-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUSqP6ih+++5KF07NXngrWf26mhSUwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE0MzAxNFoXDTI5MDQyODE0MzAxNFowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUSqP6ih++ -+5KF07NXngrWf26mhSUwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQAw13BxW11U/JL58j//Fmk7qqtrZTqXmaz1qm2WlIpJpW750MOcP4ux1uPy -eM0RdVZ4jHSMv5gtLAv/PjExBfw9n6vNCk+5GZG4Xec5DoapBZHXmfMo93sjxBFP -4x9rWn0GuwAVO9ukjYPevq2Rerilrq5VvppHtbATVNY2qecXDA== ------END CERTIFICATE----- - -# certificate for ap-southeast-2 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUFxWyAdk4oiXIOC9PxcgjYYh71mwwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE1MjE0M1oXDTI5MDQyODE1MjE0M1owXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUFxWyAdk4 -oiXIOC9PxcgjYYh71mwwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQByjeQe6lr7fiIhoGdjBXYzDfkX0lGGvMIhRh57G1bbceQfaYdZd7Ptc0jl -bpycKGaTvhUdkpMOiV2Hi9dOOYawkdhyJDstmDNKu6P9+b6Kak8He5z3NU1tUR2Y -uTwcz7Ye8Nldx//ws3raErfTI7D6s9m63OX8cAJ/f8bNgikwpw== ------END CERTIFICATE----- - # certificate for ap-southeast-3 -----BEGIN CERTIFICATE----- MIICMzCCAZygAwIBAgIGAXbVDG2yMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT @@ -395,46 +226,25 @@ WX00FTEj4hRVjameE1nENoO8Z7fUVloAFDlDo69fhkJeSvn51D1WRrPnoWGgEfr1 +OfK1bAcKTtfkkkP9r4RdwSjKzO5Zu/B+Wqm3kVEz/QNcz6npmA6 -----END CERTIFICATE----- -# certificate for us-gov-east-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIULVyrqjjwZ461qelPCiShB1KCCj4wDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDUwNzE1MjIzNloXDTI5MDUwNjE1MjIzNlowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCpohwYUVPH9I7Vbkb3WMe/JB0Y/bmfVj3VpcK445YBRO9K80al -esjgBc2tAX4KYg4Lht4EBKccLHTzaNi51YEGX1aLNrSmxhz1+WtzNLNUsyY3zD9z -vwX/3k1+JB2dRA+m+Cpwx4mjzZyAeQtHtegVaAytkmqtxQrSCexBxvqRqQIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU1ZXneBYnPvYXkHVlVjg7918V -gE8wgZkGA1UdIwSBkTCBjoAU1ZXneBYnPvYXkHVlVjg7918VgE+hYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IULVyrqjjw -Z461qelPCiShB1KCCj4wEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQBfAL/YZv0y3zmVbXjyxQCsDloeDCJjFKIu3ameEckeIWJbST9LMto0zViZ -puIAf05x6GQiEqfBMk+YMxJfcTmJB4Ebaj4egFlslJPSHyC2xuydHlr3B04INOH5 -Z2oCM68u6GGbj0jZjg7GJonkReG9N72kDva/ukwZKgq8zErQVQ== ------END CERTIFICATE----- - -# certificate for us-gov-west-1 +# certificate for us-gov-east-1 and us-gov-west-1 -----BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUe5wGF3jfb7lUHzvDxmM/ktGCLwwwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDUwNzE3MzAzMloXDTI5MDUwNjE3MzAzMlowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCpohwYUVPH9I7Vbkb3WMe/JB0Y/bmfVj3VpcK445YBRO9K80al -esjgBc2tAX4KYg4Lht4EBKccLHTzaNi51YEGX1aLNrSmxhz1+WtzNLNUsyY3zD9z -vwX/3k1+JB2dRA+m+Cpwx4mjzZyAeQtHtegVaAytkmqtxQrSCexBxvqRqQIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU1ZXneBYnPvYXkHVlVjg7918V -gE8wgZkGA1UdIwSBkTCBjoAU1ZXneBYnPvYXkHVlVjg7918VgE+hYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUe5wGF3jf -b7lUHzvDxmM/ktGCLwwwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQCbTdpx1Iob9SwUReY4exMnlwQlmkTLyA8tYGWzchCJOJJEPfsW0ryy1A0H -YIuvyUty3rJdp9ib8h3GZR71BkZnNddHhy06kPs4p8ewF8+d8OWtOJQcI+ZnFfG4 -KyM4rUsBrljpG2aOCm12iACEyrvgJJrS8VZwUDZS6mZEnn/lhA== +MIIDCzCCAnSgAwIBAgIJAIe9Hnq82O7UMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV +BAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0 +dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0yMTA3MTQx +NDI3NTdaFw0yNDA3MTMxNDI3NTdaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBX +YXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6 +b24gV2ViIFNlcnZpY2VzIExMQzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +qaIcGFFTx/SO1W5G91jHvyQdGP25n1Y91aXCuOOWAUTvSvNGpXrI4AXNrQF+CmIO +C4beBASnHCx082jYudWBBl9Wiza0psYc9flrczSzVLMmN8w/c78F/95NfiQdnUQP +pvgqcMeJo82cgHkLR7XoFWgMrZJqrcUK0gnsQcb6kakCAwEAAaOB1DCB0TALBgNV +HQ8EBAMCB4AwHQYDVR0OBBYEFNWV53gWJz72F5B1ZVY4O/dfFYBPMIGOBgNVHSME +gYYwgYOAFNWV53gWJz72F5B1ZVY4O/dfFYBPoWCkXjBcMQswCQYDVQQGEwJVUzEZ +MBcGA1UECBMQV2FzaGluZ3RvbiBTdGF0ZTEQMA4GA1UEBxMHU2VhdHRsZTEgMB4G +A1UEChMXQW1hem9uIFdlYiBTZXJ2aWNlcyBMTEOCCQCHvR56vNju1DASBgNVHRMB +Af8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4GBACrKjWj460GUPZCGm3/z0dIz +M2BPuH769wcOsqfFZcMKEysSFK91tVtUb1soFwH4/Lb/T0PqNrvtEwD1Nva5k0h2 +xZhNNRmDuhOhW1K9wCcnHGRBwY5t4lYL6hNV6hcrqYwGMjTjcAjBG2yMgznSNFle +Rwi/S3BFXISixNx9cILu -----END CERTIFICATE----- # certificate for ca-west-1 @@ -451,188 +261,4 @@ RZWaBDBJy9x8C2hW+w9lMQjFHkJ7Jy/PHCJ69EzebQIDAQABMA0GCSqGSIb3DQEB BQUAA4GBAGe9Snkz1A6rHBH6/5kDtYvtPYwhx2sXNxztbhkXErFk40Nw5l459NZx EeudxJBLoCkkSgYjhRcOZ/gvDVtWG7qyb6fAqgoisyAbk8K9LzxSim2S1nmT9vD8 4B/t/VvwQBylc+ej8kRxMH7fquZLp7IXfmtBzyUqu6Dpbne+chG2 ------END CERTIFICATE----- - -# certificate for ap-northeast-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIULgwDh7TiDrPPBJwscqDwiBHkEFQwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTEyMjMxMFoXDTI5MDQyODEyMjMxMFowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IULgwDh7Ti -DrPPBJwscqDwiBHkEFQwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQBtjAglBde1t4F9EHCZOj4qnY6Gigy07Ou54i+lR77MhbpzE8V28Li9l+YT -QMIn6SzJqU3/fIycIro1OVY1lHmaKYgPGSEZxBenSBHfzwDLRmC9oRp4QMe0BjOC -gepj1lUoiN7OA6PtA+ycNlsP0oJvdBjhvayLiuM3tUfLTrgHbw== ------END CERTIFICATE----- - -# certificate for ap-northeast-2 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUbBSn2UIO6vYk4iNWV0RPxJJtHlgwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTEzMzg0NloXDTI5MDQyODEzMzg0NlowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUbBSn2UIO -6vYk4iNWV0RPxJJtHlgwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQAmjTjalG8MGLqWTC2uYqEM8nzI3px1eo0ArvFRsyqQ3fgmWcQpxExqUqRy -l3+2134Kv8dFab04Gut5wlfRtc2OwPKKicmv/IXGN+9bKFnQFjTqif08NIzrDZch -aFT/uvxrIiM+oN2YsHq66GUhO2+xVRXDXVxM/VObFgPERbJpyA== ------END CERTIFICATE----- - -# certificate for ap-northeast-3 ------BEGIN CERTIFICATE----- -MIICMzCCAZygAwIBAgIGAYPou9weMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT -AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl -MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMjEwMTgwMTM2 -MDlaGA8yMjAxMTAxODAxMzYwOVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh -c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv -biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK -1kIcG5Q6adBXQM75GldfTSiXl7tn54p10TnspI0ErDdb2B6q2Ji/v4XBVH13ZCMg -qlRHMqV8AWI5iO6gFn2A9sN3AZXTMqwtZeiDdebq3k6Wt7ieYvpXTg0qvgsjQIov -RZWaBDBJy9x8C2hW+w9lMQjFHkJ7Jy/PHCJ69EzebQIDAQABMA0GCSqGSIb3DQEB -BQUAA4GBAGe9Snkz1A6rHBH6/5kDtYvtPYwhx2sXNxztbhkXErFk40Nw5l459NZx -EeudxJBLoCkkSgYjhRcOZ/gvDVtWG7qyb6fAqgoisyAbk8K9LzxSim2S1nmT9vD8 -4B/t/VvwQBylc+ej8kRxMH7fquZLp7IXfmtBzyUqu6Dpbne+chG2 ------END CERTIFICATE----- - -# certificate for ca-central-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUIrLgixJJB5C4G8z6pZ5rB0JU2aQwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE1MzU0M1oXDTI5MDQyODE1MzU0M1owXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUIrLgixJJ -B5C4G8z6pZ5rB0JU2aQwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQBHiQJmzyFAaSYs8SpiRijIDZW2RIo7qBKb/pI3rqK6yOWDlPuMr6yNI81D -IrKGGftg4Z+2KETYU4x76HSf0s//vfH3QA57qFaAwddhKYy4BhteFQl/Wex3xTlX -LiwI07kwJvJy3mS6UfQ4HcvZy219tY+0iyOWrz/jVxwq7TOkCw== ------END CERTIFICATE----- - -# certificate for eu-west-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUakDaQ1Zqy87Hy9ESXA1pFC116HkwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE2MTgxMFoXDTI5MDQyODE2MTgxMFowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUakDaQ1Zq -y87Hy9ESXA1pFC116HkwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQADIkn/MqaLGPuK5+prZZ5Ox4bBZLPtreO2C7r0pqU2kPM2lVPyYYydkvP0 -lgSmmsErGu/oL9JNztDe2oCA+kNy17ehcsf8cw0uP861czNFKCeU8b7FgBbL+sIm -qi33rAq6owWGi/5uEcfCR+JP7W+oSYVir5r/yDmWzx+BVH5S/g== ------END CERTIFICATE----- - -# certificate for eu-west-2 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUCgCV/DPxYNND/swDgEKGiC5I+EwwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE2MjkxNFoXDTI5MDQyODE2MjkxNFowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUCgCV/DPx -YNND/swDgEKGiC5I+EwwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQATPu/sOE2esNa4+XPEGKlEJSgqzyBSQLQc+VWo6FAJhGG9fp7D97jhHeLC -5vwfmtTAfnGBxadfAOT3ASkxnOZhXtnRna460LtnNHm7ArCVgXKJo7uBn6ViXtFh -uEEw4y6p9YaLQna+VC8Xtgw6WKq2JXuKzuhuNKSFaGGw9vRcHg== ------END CERTIFICATE----- - -# certificate for eu-west-3 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUaC9fX57UDr6u1vBvsCsECKBZQyIwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE2MzczOFoXDTI5MDQyODE2MzczOFowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUaC9fX57U -Dr6u1vBvsCsECKBZQyIwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQCARv1bQEDaMEzYI0nPlu8GHcMXgmgA94HyrXhMMcaIlQwocGBs6VILGVhM -TXP2r3JFaPEpmXSQNQHvGA13clKwAZbni8wtzv6qXb4L4muF34iQRHF0nYrEDoK7 -mMPR8+oXKKuPO/mv/XKo6XAV5DDERdSYHX5kkA2R9wtvyZjPnQ== ------END CERTIFICATE----- - -# certificate for eu-north-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUN1c9U6U/xiVDFgJcYKZB4NkH1QEwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE2MDYwM1oXDTI5MDQyODE2MDYwM1owXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUN1c9U6U/ -xiVDFgJcYKZB4NkH1QEwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQBTIQdoFSDRHkpqNPUbZ9WXR2O5v/9bpmHojMYZb3Hw46wsaRso7STiGGX/ -tRqjIkPUIXsdhZ3+7S/RmhFznmZc8e0bjU4n5vi9CJtQSt+1u4E17+V2bF+D3h/7 -wcfE0l3414Q8JaTDtfEf/aF3F0uyBvr4MDMd7mFvAMmDmBPSlA== ------END CERTIFICATE----- - -# certificate for sa-east-1 ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIUX4Bh4MQ86Roh37VDRRX1MNOB3TcwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAO -BgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExD -MB4XDTI0MDQyOTE2NDYwOVoXDTI5MDQyODE2NDYwOVowXDELMAkGA1UEBhMCVVMx -GTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAe -BgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCHvRjf/0kStpJ248khtIaN8qkDN3tkw4VjvA9nvPl2anJO+eIB -UqPfQG09kZlwpWpmyO8bGB2RWqWxCwuB/dcnIob6w420k9WY5C0IIGtDRNauN3ku -vGXkw3HEnF0EjYr0pcyWUvByWY4KswZV42X7Y7XSS13hOIcL6NLA+H94/QIDAQAB -o4HfMIHcMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUJdbMCBXKtvCcWdwUUizvtUF2 -UTgwgZkGA1UdIwSBkTCBjoAUJdbMCBXKtvCcWdwUUizvtUF2UTihYKReMFwxCzAJ -BgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdT -ZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQ4IUX4Bh4MQ8 -6Roh37VDRRX1MNOB3TcwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsF -AAOBgQBnhocfH6ZIX6F5K9+Y9V4HFk8vSaaKL5ytw/P5td1h9ej94KF3xkZ5fyjN -URvGQv3kNmNJBoNarcP9I7JIMjsNPmVzqWawyCEGCZImoARxSS3Fc5EAs2PyBfcD -9nCtzMTaKO09Xyq0wqXVYn1xJsE5d5yBDsGrzaTHKjxo61+ezQ== ------END CERTIFICATE----- +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/azure.go b/vendor/github.com/smallstep/certificates/authority/provisioner/azure.go index 0a86b64..a9d5d1f 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/azure.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/azure.go @@ -251,14 +251,14 @@ func (p *Azure) Init(config Config) (err error) { p.assertConfig() // Decode and validate openid-configuration endpoint - if err = getAndDecode(http.DefaultClient, p.config.oidcDiscoveryURL, &p.oidcConfig); err != nil { + if err = getAndDecode(p.config.oidcDiscoveryURL, &p.oidcConfig); err != nil { return } if err := p.oidcConfig.Validate(); err != nil { return errors.Wrapf(err, "error parsing %s", p.config.oidcDiscoveryURL) } // Get JWK key set - if p.keyStore, err = newKeyStore(http.DefaultClient, p.oidcConfig.JWKSetURI); err != nil { + if p.keyStore, err = newKeyStore(p.oidcConfig.JWKSetURI); err != nil { return } @@ -379,7 +379,7 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption, // name will work only inside the virtual network so = append(so, commonNameValidator(name), - dnsNamesSubsetValidator([]string{name}), + dnsNamesValidator([]string{name}), ipAddressesValidator(nil), emailAddressesValidator(nil), newURIsValidator(ctx, nil), diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/claims.go b/vendor/github.com/smallstep/certificates/authority/provisioner/claims.go index 993bf49..dcf679b 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/claims.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/claims.go @@ -234,24 +234,24 @@ func (c *Claimer) IsSSHCAEnabled() bool { // Validate validates and modifies the Claims with default values. func (c *Claimer) Validate() error { var ( - minDur = c.MinTLSCertDuration() - maxDur = c.MaxTLSCertDuration() - defDur = c.DefaultTLSCertDuration() + min = c.MinTLSCertDuration() + max = c.MaxTLSCertDuration() + def = c.DefaultTLSCertDuration() ) switch { - case minDur <= 0: + case min <= 0: return errors.Errorf("claims: MinTLSCertDuration must be greater than 0") - case maxDur <= 0: + case max <= 0: return errors.Errorf("claims: MaxTLSCertDuration must be greater than 0") - case defDur <= 0: + case def <= 0: return errors.Errorf("claims: DefaultTLSCertDuration must be greater than 0") - case maxDur < minDur: + case max < min: return errors.Errorf("claims: MaxCertDuration cannot be less "+ - "than MinCertDuration: MaxCertDuration - %v, MinCertDuration - %v", maxDur, minDur) - case defDur < minDur: - return errors.Errorf("claims: DefaultCertDuration cannot be less than MinCertDuration: DefaultCertDuration - %v, MinCertDuration - %v", defDur, minDur) - case maxDur < defDur: - return errors.Errorf("claims: MaxCertDuration cannot be less than DefaultCertDuration: MaxCertDuration - %v, DefaultCertDuration - %v", maxDur, defDur) + "than MinCertDuration: MaxCertDuration - %v, MinCertDuration - %v", max, min) + case def < min: + return errors.Errorf("claims: DefaultCertDuration cannot be less than MinCertDuration: DefaultCertDuration - %v, MinCertDuration - %v", def, min) + case max < def: + return errors.Errorf("claims: MaxCertDuration cannot be less than DefaultCertDuration: MaxCertDuration - %v, DefaultCertDuration - %v", max, def) default: return nil } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/controller.go b/vendor/github.com/smallstep/certificates/authority/provisioner/controller.go index 8d95aaf..09f6a6b 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/controller.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/controller.go @@ -26,7 +26,6 @@ type Controller struct { policy *policyEngine webhookClient *http.Client webhooks []*Webhook - httpClient *http.Client } // NewController initializes a new provisioner controller. @@ -49,19 +48,9 @@ func NewController(p Interface, claims *Claims, config Config, options *Options) policy: policy, webhookClient: config.WebhookClient, webhooks: options.GetWebhooks(), - httpClient: config.HTTPClient, }, nil } -// GetHTTPClient returns the configured HTTP client or the default one if none -// is configured. -func (c *Controller) GetHTTPClient() *http.Client { - if c.httpClient != nil { - return c.httpClient - } - return &http.Client{} -} - // GetIdentity returns the identity for a given email. func (c *Controller) GetIdentity(ctx context.Context, email string) (*Identity, error) { if c.IdentityFunc != nil { diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/gcp.go b/vendor/github.com/smallstep/certificates/authority/provisioner/gcp.go index c63a29c..2296b1b 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/gcp.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/gcp.go @@ -30,12 +30,6 @@ const gcpCertsURL = "https://www.googleapis.com/oauth2/v3/certs" // gcpIdentityURL is the base url for the identity document in GCP. const gcpIdentityURL = "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity" -// DefaultDisableSSHCAHost is the default value for SSH Host CA used when DisableSSHCAHost is not set -var DefaultDisableSSHCAHost = false - -// DefaultDisableSSHCAUser is the default value for SSH User CA used when DisableSSHCAUser is not set -var DefaultDisableSSHCAUser = true - // gcpPayload extends jwt.Claims with custom GCP attributes. type gcpPayload struct { jose.Claims @@ -95,8 +89,6 @@ type GCP struct { ProjectIDs []string `json:"projectIDs"` DisableCustomSANs bool `json:"disableCustomSANs"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` - DisableSSHCAUser *bool `json:"disableSSHCAUser,omitempty"` - DisableSSHCAHost *bool `json:"disableSSHCAHost,omitempty"` InstanceAge Duration `json:"instanceAge,omitempty"` Claims *Claims `json:"claims,omitempty"` Options *Options `json:"options,omitempty"` @@ -207,14 +199,6 @@ func (p *GCP) GetIdentityToken(subject, caURL string) (string, error) { // Init validates and initializes the GCP provisioner. func (p *GCP) Init(config Config) (err error) { - if p.DisableSSHCAHost == nil { - p.DisableSSHCAHost = &DefaultDisableSSHCAHost - } - - if p.DisableSSHCAUser == nil { - p.DisableSSHCAUser = &DefaultDisableSSHCAUser - } - switch { case p.Type == "": return errors.New("provisioner type cannot be empty") @@ -228,7 +212,7 @@ func (p *GCP) Init(config Config) (err error) { p.assertConfig() // Initialize key store - if p.keyStore, err = newKeyStore(http.DefaultClient, p.config.CertsURL); err != nil { + if p.keyStore, err = newKeyStore(p.config.CertsURL); err != nil { return } @@ -265,7 +249,7 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er commonNameSliceValidator([]string{ ce.InstanceName, ce.InstanceID, dnsName1, dnsName2, }), - dnsNamesSubsetValidator([]string{ + dnsNamesValidator([]string{ dnsName1, dnsName2, }), ipAddressesValidator(nil), @@ -403,41 +387,31 @@ func (p *GCP) authorizeToken(token string) (*gcpPayload, error) { } // AuthorizeSSHSign returns the list of SignOption for a SignSSH request. -func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, error) { - certType, hasCertType := CertTypeFromContext(ctx) - if !hasCertType { - certType = SSHHostCert - } - - err := p.isUnauthorizedToIssueSSHCert(certType) - if err != nil { - return nil, err +func (p *GCP) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, error) { + if !p.ctl.Claimer.IsSSHCAEnabled() { + return nil, errs.Unauthorized("gcp.AuthorizeSSHSign; sshCA is disabled for gcp provisioner '%s'", p.GetName()) } - claims, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSSHSign") } - var principals []string - var keyID string - var defaults SignSSHOptions - var ct sshutil.CertType - var template string + ce := claims.Google.ComputeEngine + signOptions := []SignOption{} - switch certType { - case SSHHostCert: - defaults, keyID, principals, ct, template = p.genHostOptions(ctx, claims) - case SSHUserCert: - defaults, keyID, principals, ct, template = p.genUserOptions(ctx, claims) - default: - return nil, errs.Unauthorized("gcp.AuthorizeSSHSign; invalid requested certType") + // Enforce host certificate. + defaults := SignSSHOptions{ + CertType: SSHHostCert, } - signOptions := []SignOption{} + // Validated principals. + principals := []string{ + fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID), + fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID), + } - // Only enforce known principals if disable custom sans is true, or it is a user cert request - if p.DisableCustomSANs || certType == SSHUserCert { + // Only enforce known principals if disable custom sans is true. + if p.DisableCustomSANs { defaults.Principals = principals } else { // Check that at least one principal is sent in the request. @@ -447,12 +421,12 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, } // Certificate templates. - data := sshutil.CreateTemplateData(ct, keyID, principals) + data := sshutil.CreateTemplateData(sshutil.HostCert, ce.InstanceName, principals) if v, err := unsafeParseSigned(token); err == nil { data.SetToken(v) } - templateOptions, err := CustomSSHTemplateOptions(p.Options, data, template) + templateOptions, err := CustomSSHTemplateOptions(p.Options, data, sshutil.DefaultIIDTemplate) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "gcp.AuthorizeSSHSign") } @@ -471,54 +445,12 @@ func (p *GCP) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption, // Require all the fields in the SSH certificate &sshCertDefaultValidator{}, // Ensure that all principal names are allowed - newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), p.ctl.getPolicy().getSSHUser()), + newSSHNamePolicyValidator(p.ctl.getPolicy().getSSHHost(), nil), // Call webhooks p.ctl.newWebhookController( data, linkedca.Webhook_SSH, - webhook.WithAuthorizationPrincipal(keyID), + webhook.WithAuthorizationPrincipal(ce.InstanceID), ), ), nil } - -func (p *GCP) genHostOptions(_ context.Context, claims *gcpPayload) (SignSSHOptions, string, []string, sshutil.CertType, string) { - ce := claims.Google.ComputeEngine - keyID := ce.InstanceName - - principals := []string{ - fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID), - fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID), - } - - return SignSSHOptions{CertType: SSHHostCert}, keyID, principals, sshutil.HostCert, sshutil.DefaultIIDTemplate -} - -func FormatServiceAccountUsername(serviceAccountID string) string { - return fmt.Sprintf("sa_%v", serviceAccountID) -} - -func (p *GCP) genUserOptions(_ context.Context, claims *gcpPayload) (SignSSHOptions, string, []string, sshutil.CertType, string) { - keyID := claims.Email - principals := []string{ - FormatServiceAccountUsername(claims.Subject), - claims.Email, - } - - return SignSSHOptions{CertType: SSHUserCert}, keyID, principals, sshutil.UserCert, sshutil.DefaultTemplate -} - -func (p *GCP) isUnauthorizedToIssueSSHCert(certType string) error { - if !p.ctl.Claimer.IsSSHCAEnabled() { - return errs.Unauthorized("gcp.AuthorizeSSHSign; sshCA is disabled for gcp provisioner '%s'", p.GetName()) - } - - if certType == SSHHostCert && *p.DisableSSHCAHost { - return errs.Unauthorized("gcp.AuthorizeSSHSign; sshCA for Hosts is disabled for gcp provisioner '%s'", p.GetName()) - } - - if certType == SSHUserCert && *p.DisableSSHCAUser { - return errs.Unauthorized("gcp.AuthorizeSSHSign; sshCA for Users is disabled for gcp provisioner '%s'", p.GetName()) - } - - return nil -} diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/jwk.go b/vendor/github.com/smallstep/certificates/authority/provisioner/jwk.go index 70a6706..13e8bd4 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/jwk.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/jwk.go @@ -19,9 +19,8 @@ import ( // jwtPayload extends jwt.Claims with step attributes. type jwtPayload struct { jose.Claims - SANs []string `json:"sans,omitempty"` - Step *stepPayload `json:"step,omitempty"` - Confirmation *cnfPayload `json:"cnf,omitempty"` + SANs []string `json:"sans,omitempty"` + Step *stepPayload `json:"step,omitempty"` } type stepPayload struct { @@ -29,10 +28,6 @@ type stepPayload struct { RA *RAInfo `json:"ra,omitempty"` } -type cnfPayload struct { - Fingerprint string `json:"x5rt#S256,omitempty"` -} - // JWK is the default provisioner, an entity that can sign tokens necessary for // signature requests. type JWK struct { @@ -188,12 +183,6 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er } } - // Check the fingerprint of the certificate request if given. - var fingerprint string - if claims.Confirmation != nil { - fingerprint = claims.Confirmation.Fingerprint - } - return []SignOption{ self, templateOptions, @@ -201,7 +190,6 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID).WithControllerOptions(p.ctl), profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()), // validators - csrFingerprintValidator(fingerprint), commonNameSliceValidator(append([]string{claims.Subject}, claims.SANs...)), defaultPublicKeyValidator{}, newDefaultSANsValidator(ctx, claims.SANs), @@ -249,7 +237,7 @@ func (p *JWK) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e // Use options in the token. if opts.CertType != "" { if certType, err = sshutil.CertTypeFromString(opts.CertType); err != nil { - return nil, errs.BadRequestErr(err, err.Error()) //nolint:govet // allow non-constant error messages + return nil, errs.BadRequestErr(err, err.Error()) } } if opts.KeyID != "" { diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/keystore.go b/vendor/github.com/smallstep/certificates/authority/provisioner/keystore.go index 23a4e9a..aeaad6a 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/keystore.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/keystore.go @@ -22,7 +22,6 @@ var maxAgeRegex = regexp.MustCompile(`max-age=(\d+)`) type keyStore struct { sync.RWMutex - client *http.Client uri string keySet jose.JSONWebKeySet timer *time.Timer @@ -30,13 +29,12 @@ type keyStore struct { jitter time.Duration } -func newKeyStore(client *http.Client, uri string) (*keyStore, error) { - keys, age, err := getKeysFromJWKsURI(client, uri) +func newKeyStore(uri string) (*keyStore, error) { + keys, age, err := getKeysFromJWKsURI(uri) if err != nil { return nil, err } ks := &keyStore{ - client: client, uri: uri, keySet: keys, expiry: getExpirationTime(age), @@ -66,7 +64,7 @@ func (ks *keyStore) Get(kid string) (keys []jose.JSONWebKey) { func (ks *keyStore) reload() { var next time.Duration - keys, age, err := getKeysFromJWKsURI(ks.client, ks.uri) + keys, age, err := getKeysFromJWKsURI(ks.uri) if err != nil { next = ks.nextReloadDuration(ks.jitter / 2) } else { @@ -92,9 +90,9 @@ func (ks *keyStore) nextReloadDuration(age time.Duration) time.Duration { return abs(age) } -func getKeysFromJWKsURI(client *http.Client, uri string) (jose.JSONWebKeySet, time.Duration, error) { +func getKeysFromJWKsURI(uri string) (jose.JSONWebKeySet, time.Duration, error) { var keys jose.JSONWebKeySet - resp, err := client.Get(uri) + resp, err := http.Get(uri) //nolint:gosec // openid-configuration jwks_uri if err != nil { return keys, 0, errors.Wrapf(err, "failed to connect to %s", uri) } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/method.go b/vendor/github.com/smallstep/certificates/authority/provisioner/method.go index d01ce12..19aa622 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/method.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/method.go @@ -78,17 +78,3 @@ func TokenFromContext(ctx context.Context) (string, bool) { token, ok := ctx.Value(tokenKey{}).(string) return token, ok } - -// The key to save the certTypeKey in the context. -type certTypeKey struct{} - -// NewContextWithCertType creates a new context with the given CertType. -func NewContextWithCertType(ctx context.Context, certType string) context.Context { - return context.WithValue(ctx, certTypeKey{}, certType) -} - -// CertTypeFromContext returns the certType stored in the given context. -func CertTypeFromContext(ctx context.Context) (string, bool) { - certType, ok := ctx.Value(certTypeKey{}).(string) - return certType, ok -} diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/nebula.go b/vendor/github.com/smallstep/certificates/authority/provisioner/nebula.go index fa9c283..66c523d 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/nebula.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/nebula.go @@ -2,13 +2,9 @@ package provisioner import ( "context" - "crypto/ecdh" - "crypto/ecdsa" "crypto/ed25519" - "crypto/elliptic" "crypto/x509" "encoding/base64" - "math/big" "net" "time" @@ -341,23 +337,10 @@ func (p *Nebula) authorizeToken(token string, audiences []string) (*nebula.Nebul return nil, nil, errs.Unauthorized("token is not valid: failed to verify certificate against configured CA") } - var pub any - switch { - case c.Details.Curve == nebula.Curve_P256: - // When Nebula is used with ECDSA P-256 keys, both CAs and clients use the same type. - ecdhPub, err := ecdh.P256().NewPublicKey(c.Details.PublicKey) - if err != nil { - return nil, nil, errs.UnauthorizedErr(err, errs.WithMessage("failed to parse nebula public key")) - } - publicKeyBytes := ecdhPub.Bytes() - pub = &ecdsa.PublicKey{ // convert back to *ecdsa.PublicKey, because our jose package nor go-jose supports *ecdh.PublicKey - Curve: elliptic.P256(), - X: big.NewInt(0).SetBytes(publicKeyBytes[1:33]), - Y: big.NewInt(0).SetBytes(publicKeyBytes[33:]), - } - case c.Details.IsCA: + var pub interface{} + if c.Details.IsCA { pub = ed25519.PublicKey(c.Details.PublicKey) - default: + } else { pub = x25519.PublicKey(c.Details.PublicKey) } @@ -375,7 +358,6 @@ func (p *Nebula) authorizeToken(token string, audiences []string) (*nebula.Nebul }, time.Minute); err != nil { return nil, nil, errs.UnauthorizedErr(err, errs.WithMessage("token is not valid: invalid claims")) } - // Validate token and subject too. if !matchesAudience(claims.Audience, audiences) { return nil, nil, errs.Unauthorized("token is not valid: invalid claims") diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/oidc.go b/vendor/github.com/smallstep/certificates/authority/provisioner/oidc.go index 25d29b5..06823e2 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/oidc.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/oidc.go @@ -93,8 +93,6 @@ type OIDC struct { ListenAddress string `json:"listenAddress,omitempty"` Claims *Claims `json:"claims,omitempty"` Options *Options `json:"options,omitempty"` - Scopes []string `json:"scopes,omitempty"` - AuthParams []string `json:"authParams,omitempty"` configuration openIDConfiguration keyStore *keyStore ctl *Controller @@ -184,29 +182,23 @@ func (o *OIDC) Init(config Config) (err error) { if !strings.Contains(u.Path, "/.well-known/openid-configuration") { u.Path = path.Join(u.Path, "/.well-known/openid-configuration") } - - // Initialize the common provisioner controller - o.ctl, err = NewController(o, o.Claims, config, o.Options) - if err != nil { - return err - } - - // Decode and validate openid-configuration - httpClient := o.ctl.GetHTTPClient() - if err := getAndDecode(httpClient, u.String(), &o.configuration); err != nil { + if err := getAndDecode(u.String(), &o.configuration); err != nil { return err } if err := o.configuration.Validate(); err != nil { return errors.Wrapf(err, "error parsing %s", o.ConfigurationEndpoint) } - // Replace {tenantid} with the configured one if o.TenantID != "" { o.configuration.Issuer = strings.ReplaceAll(o.configuration.Issuer, "{tenantid}", o.TenantID) } - // Get JWK key set - o.keyStore, err = newKeyStore(httpClient, o.configuration.JWKSetURI) + o.keyStore, err = newKeyStore(o.configuration.JWKSetURI) + if err != nil { + return err + } + + o.ctl, err = NewController(o, o.Claims, config, o.Options) return } @@ -485,8 +477,8 @@ func (o *OIDC) AuthorizeSSHRevoke(_ context.Context, token string) error { return errs.Unauthorized("oidc.AuthorizeSSHRevoke; cannot revoke with non-admin oidc token") } -func getAndDecode(client *http.Client, uri string, v interface{}) error { - resp, err := client.Get(uri) +func getAndDecode(uri string, v interface{}) error { + resp, err := http.Get(uri) //nolint:gosec // openid-configuration uri if err != nil { return errors.Wrapf(err, "failed to connect to %s", uri) } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/options.go b/vendor/github.com/smallstep/certificates/authority/provisioner/options.go index f68e9da..cbce43d 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/options.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/options.go @@ -6,12 +6,11 @@ import ( "github.com/pkg/errors" - "github.com/smallstep/cli-utils/step" + "go.step.sm/cli-utils/step" "go.step.sm/crypto/jose" "go.step.sm/crypto/x509util" "github.com/smallstep/certificates/authority/policy" - "github.com/smallstep/certificates/authority/provisioner/wire" ) // CertificateOptions is an interface that returns a list of options passed when @@ -31,10 +30,9 @@ func (fn certificateOptionsFunc) Options(so SignOptions) []x509util.Option { type Options struct { X509 *X509Options `json:"x509,omitempty"` SSH *SSHOptions `json:"ssh,omitempty"` + // Webhooks is a list of webhooks that can augment template data Webhooks []*Webhook `json:"webhooks,omitempty"` - // Wire holds the options used for the ACME Wire integration - Wire *wire.Options `json:"wire,omitempty"` } // GetX509Options returns the X.509 options. @@ -53,18 +51,6 @@ func (o *Options) GetSSHOptions() *SSHOptions { return o.SSH } -// GetWireOptions returns the Wire options if available. It -// returns an error if they're not available. -func (o *Options) GetWireOptions() (*wire.Options, error) { - if o == nil { - return nil, errors.New("no options available") - } - if o.Wire == nil { - return nil, errors.New("no Wire options available") - } - return o.Wire, nil -} - // GetWebhooks returns the webhooks options. func (o *Options) GetWebhooks() []*Webhook { if o == nil { diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/provisioner.go b/vendor/github.com/smallstep/certificates/authority/provisioner/provisioner.go index 24792f6..73397a3 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/provisioner.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/provisioner.go @@ -34,31 +34,6 @@ type Interface interface { AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certificate, []SignOption, error) } -// Uninitialized represents a disabled provisioner. Uninitialized provisioners -// are created when the Init methods fails. -type Uninitialized struct { - Interface - Reason error -} - -// MarshalJSON returns the JSON encoding of the provisioner with the disabled -// reason. -func (p Uninitialized) MarshalJSON() ([]byte, error) { - provisionerJSON, err := json.Marshal(p.Interface) - if err != nil { - return nil, err - } - reasonJSON, err := json.Marshal(struct { - State string `json:"state"` - StateReason string `json:"stateReason"` - }{"Uninitialized", p.Reason.Error()}) - if err != nil { - return nil, err - } - reasonJSON[0] = ',' - return append(provisionerJSON[:len(provisionerJSON)-1], reasonJSON...), nil -} - // ErrAllowTokenReuse is an error that is returned by provisioners that allows // the reuse of tokens. // @@ -246,7 +221,7 @@ type Config struct { Claims Claims // Audiences are the audiences used in the default provisioner, (JWK). Audiences Audiences - // SSHKeys are the root SSH public keys. + // SSHKeys are the root SSH public keys SSHKeys *SSHKeys // GetIdentityFunc is a function that returns an identity that will be // used by the provisioner to populate certificate attributes. @@ -257,13 +232,10 @@ type Config struct { // AuthorizeSSHRenewFunc is a function that returns nil if a given SSH // certificate can be renewed. AuthorizeSSHRenewFunc AuthorizeSSHRenewFunc - // WebhookClient is an HTTP client used when performing webhook requests. + // WebhookClient is an http client to use in webhook request WebhookClient *http.Client // SCEPKeyManager, if defined, is the interface used by SCEP provisioners. SCEPKeyManager SCEPKeyManager - // HTTPClient is an HTTP client that trusts the system cert pool and the CA - // roots. - HTTPClient *http.Client } type provisioner struct { diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/scep.go b/vendor/github.com/smallstep/certificates/authority/provisioner/scep.go index 0bdaf3e..7213285 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/scep.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/scep.go @@ -15,7 +15,6 @@ import ( "go.step.sm/crypto/kms" kmsapi "go.step.sm/crypto/kms/apiv1" - "go.step.sm/crypto/x509util" "go.step.sm/linkedca" "github.com/smallstep/certificates/webhook" @@ -146,33 +145,25 @@ var ( // that case, the other webhooks will be skipped. If none of // the webhooks indicates the value of the challenge was accepted, // an error is returned. -func (c *challengeValidationController) Validate(ctx context.Context, csr *x509.CertificateRequest, provisionerName, challenge, transactionID string) ([]SignCSROption, error) { - var opts []SignCSROption - +func (c *challengeValidationController) Validate(ctx context.Context, csr *x509.CertificateRequest, provisionerName, challenge, transactionID string) error { for _, wh := range c.webhooks { req, err := webhook.NewRequestBody(webhook.WithX509CertificateRequest(csr)) if err != nil { - return nil, fmt.Errorf("failed creating new webhook request: %w", err) + return fmt.Errorf("failed creating new webhook request: %w", err) } req.ProvisionerName = provisionerName req.SCEPChallenge = challenge req.SCEPTransactionID = transactionID resp, err := wh.DoWithContext(ctx, c.client, req, nil) // TODO(hs): support templated URL? Requires some refactoring if err != nil { - return nil, fmt.Errorf("failed executing webhook request: %w", err) + return fmt.Errorf("failed executing webhook request: %w", err) } if resp.Allow { - opts = append(opts, TemplateDataModifierFunc(func(data x509util.TemplateData) { - data.SetWebhook(wh.Name, resp.Data) - })) + return nil // return early when response is positive } } - if len(opts) == 0 { - return nil, ErrSCEPChallengeInvalid - } - - return opts, nil + return ErrSCEPChallengeInvalid } type notificationController struct { @@ -449,18 +440,18 @@ func (s *SCEP) GetContentEncryptionAlgorithm() int { // ValidateChallenge validates the provided challenge. It starts by // selecting the validation method to use, then performs validation // according to that method. -func (s *SCEP) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) ([]SignCSROption, error) { +func (s *SCEP) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error { if s.challengeValidationController == nil { - return nil, fmt.Errorf("provisioner %q wasn't initialized", s.Name) + return fmt.Errorf("provisioner %q wasn't initialized", s.Name) } switch s.selectValidationMethod() { case validationMethodWebhook: return s.challengeValidationController.Validate(ctx, csr, s.Name, challenge, transactionID) default: if subtle.ConstantTimeCompare([]byte(s.ChallengePassword), []byte(challenge)) == 0 { - return nil, errors.New("invalid challenge password provided") + return errors.New("invalid challenge password provided") } - return []SignCSROption{}, nil + return nil } } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/sign_options.go b/vendor/github.com/smallstep/certificates/authority/provisioner/sign_options.go index fc842c4..fec9b9f 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/sign_options.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/sign_options.go @@ -5,10 +5,7 @@ import ( "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" - "crypto/sha256" - "crypto/subtle" "crypto/x509" - "encoding/base64" "encoding/json" "net" "net/http" @@ -190,27 +187,6 @@ func (v dnsNamesValidator) Valid(req *x509.CertificateRequest) error { return nil } -// dnsNamesSubsetValidator validates the DNS name SANs of a certificate request. -type dnsNamesSubsetValidator []string - -// Valid checks that all DNS name SANs in the certificate request are present in -// the allowed list of DNS names. -func (v dnsNamesSubsetValidator) Valid(req *x509.CertificateRequest) error { - if len(req.DNSNames) == 0 { - return nil - } - allowed := make(map[string]struct{}, len(v)) - for _, s := range v { - allowed[s] = struct{}{} - } - for _, s := range req.DNSNames { - if _, ok := allowed[s]; !ok { - return errs.Forbidden("certificate request contains unauthorized DNS names - got %v, allowed %v", req.DNSNames, v) - } - } - return nil -} - // ipAddressesValidator validates the IP addresses SAN of a certificate request. type ipAddressesValidator []net.IP @@ -323,19 +299,14 @@ func (v defaultSANsValidator) Valid(req *x509.CertificateRequest) (err error) { // duration. type profileDefaultDuration time.Duration -// Modify sets the certificate NotBefore and NotAfter using the following order: -// - From the SignOptions that we get from flags. -// - From x509.Certificate that we get from the template. -// - NotBefore from the current time with a backdate. -// - NotAfter from NotBefore plus the duration in v. func (v profileDefaultDuration) Modify(cert *x509.Certificate, so SignOptions) error { var backdate time.Duration - notBefore := timeOr(so.NotBefore.Time(), cert.NotBefore) + notBefore := so.NotBefore.Time() if notBefore.IsZero() { notBefore = now() backdate = -1 * so.Backdate } - notAfter := timeOr(so.NotAfter.RelativeTime(notBefore), cert.NotAfter) + notAfter := so.NotAfter.RelativeTime(notBefore) if notAfter.IsZero() { if v != 0 { notAfter = notBefore.Add(time.Duration(v)) @@ -356,17 +327,11 @@ type profileLimitDuration struct { notBefore, notAfter time.Time } -// Modify sets the certificate NotBefore and NotAfter but limits the validity -// period to the certificate to one that is superficially imposed. -// -// The expected NotBefore and NotAfter are set using the following order: -// - From the SignOptions that we get from flags. -// - From x509.Certificate that we get from the template. -// - NotBefore from the current time with a backdate. -// - NotAfter from NotBefore plus the duration v or the notAfter in v if lower. +// Option returns an x509util option that limits the validity period of a +// certificate to one that is superficially imposed. func (v profileLimitDuration) Modify(cert *x509.Certificate, so SignOptions) error { var backdate time.Duration - notBefore := timeOr(so.NotBefore.Time(), cert.NotBefore) + notBefore := so.NotBefore.Time() if notBefore.IsZero() { notBefore = now() backdate = -1 * so.Backdate @@ -377,7 +342,7 @@ func (v profileLimitDuration) Modify(cert *x509.Certificate, so SignOptions) err notBefore, v.notBefore) } - notAfter := timeOr(so.NotAfter.RelativeTime(notBefore), cert.NotAfter) + notAfter := so.NotAfter.RelativeTime(notBefore) if notAfter.After(v.notAfter) { return errs.Forbidden( "requested certificate notAfter (%s) is after the expiration of the provisioning credential (%s)", @@ -404,8 +369,8 @@ type validityValidator struct { } // newValidityValidator return a new validity validator. -func newValidityValidator(minDur, maxDur time.Duration) *validityValidator { - return &validityValidator{min: minDur, max: maxDur} +func newValidityValidator(min, max time.Duration) *validityValidator { + return &validityValidator{min: min, max: max} } // Valid validates the certificate validity settings (notBefore/notAfter) and @@ -527,46 +492,3 @@ func (o *provisionerExtensionOption) Modify(cert *x509.Certificate, _ SignOption cert.ExtraExtensions = append(cert.ExtraExtensions, ext) return nil } - -// csrFingerprintValidator is a CertificateRequestValidator that checks the -// fingerprint of the certificate request with the provided one. -type csrFingerprintValidator string - -func (s csrFingerprintValidator) Valid(cr *x509.CertificateRequest) error { - if s != "" { - expected, err := base64.RawURLEncoding.DecodeString(string(s)) - if err != nil { - return errs.ForbiddenErr(err, "error decoding fingerprint") - } - sum := sha256.Sum256(cr.Raw) - if subtle.ConstantTimeCompare(expected, sum[:]) != 1 { - return errs.Forbidden("certificate request fingerprint does not match %q", s) - } - } - return nil -} - -// SignCSROption is the interface used to collect extra options in the SignCSR -// method of the SCEP authority. -type SignCSROption any - -// TemplateDataModifier is an interface that allows to modify template data. -type TemplateDataModifier interface { - Modify(data x509util.TemplateData) -} - -type templateDataModifier struct { - fn func(x509util.TemplateData) -} - -func (t *templateDataModifier) Modify(data x509util.TemplateData) { - t.fn(data) -} - -// TemplateDataModifierFunc returns a TemplateDataModifier with the given -// function. -func TemplateDataModifierFunc(fn func(data x509util.TemplateData)) TemplateDataModifier { - return &templateDataModifier{ - fn: fn, - } -} diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/sign_ssh_options.go b/vendor/github.com/smallstep/certificates/authority/provisioner/sign_ssh_options.go index 512a8f0..ee74ded 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/sign_ssh_options.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/sign_ssh_options.go @@ -44,13 +44,6 @@ type SSHCertOptionsValidator interface { Valid(got SignSSHOptions) error } -// SSHPublicKeyValidator is the interface used to validate the public key of an -// SSH certificate. -type SSHPublicKeyValidator interface { - SignOption - Valid(got ssh.PublicKey) error -} - // SignSSHOptions contains the options that can be passed to the SignSSH method. type SignSSHOptions struct { CertType string `json:"certType"` @@ -283,14 +276,14 @@ func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SignSSHOpti return errs.BadRequest("ssh certificate validBefore cannot be before validAfter") } - var minDur, maxDur time.Duration + var min, max time.Duration switch cert.CertType { case ssh.UserCert: - minDur = v.MinUserSSHCertDuration() - maxDur = v.MaxUserSSHCertDuration() + min = v.MinUserSSHCertDuration() + max = v.MaxUserSSHCertDuration() case ssh.HostCert: - minDur = v.MinHostSSHCertDuration() - maxDur = v.MaxHostSSHCertDuration() + min = v.MinHostSSHCertDuration() + max = v.MaxHostSSHCertDuration() case 0: return errs.BadRequest("ssh certificate type has not been set") default: @@ -302,10 +295,10 @@ func (v *sshCertValidityValidator) Valid(cert *ssh.Certificate, opts SignSSHOpti dur := time.Duration(cert.ValidBefore-cert.ValidAfter) * time.Second switch { - case dur < minDur: - return errs.Forbidden("requested duration of %s is less than minimum accepted duration for selected provisioner of %s", dur, minDur) - case dur > maxDur+opts.Backdate: - return errs.Forbidden("requested duration of %s is greater than maximum accepted duration for selected provisioner of %s", dur, maxDur+opts.Backdate) + case dur < min: + return errs.Forbidden("requested duration of %s is less than minimum accepted duration for selected provisioner of %s", dur, min) + case dur > max+opts.Backdate: + return errs.Forbidden("requested duration of %s is greater than maximum accepted duration for selected provisioner of %s", dur, max+opts.Backdate) default: return nil } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/ssh_options.go b/vendor/github.com/smallstep/certificates/authority/provisioner/ssh_options.go index def2ec7..e870ff3 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/ssh_options.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/ssh_options.go @@ -5,8 +5,7 @@ import ( "strings" "github.com/pkg/errors" - - "github.com/smallstep/cli-utils/step" + "go.step.sm/cli-utils/step" "go.step.sm/crypto/sshutil" "github.com/smallstep/certificates/authority/policy" diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/timeduration.go b/vendor/github.com/smallstep/certificates/authority/provisioner/timeduration.go index 39bbb19..7d19721 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/timeduration.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/timeduration.go @@ -11,17 +11,6 @@ var now = func() time.Time { return time.Now().UTC() } -// timeOr returns the first of its arguments that is not equal to the zero time. -// This method can be replaced with cmp.Or when step-ca requires Go 1.22. -func timeOr(ts ...time.Time) time.Time { - for _, t := range ts { - if !t.IsZero() { - return t - } - } - return time.Time{} -} - // TimeDuration is a type that represents a time but the JSON unmarshaling can // use a time using the RFC 3339 format or a time.Duration string. If a duration // is used, the time will be set on the first call to TimeDuration.Time. diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/webhook.go b/vendor/github.com/smallstep/certificates/authority/provisioner/webhook.go index 2822418..05f972f 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/webhook.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/webhook.go @@ -65,9 +65,6 @@ func (wc *WebhookController) Enrich(ctx context.Context, req *webhook.RequestBod return err } if !resp.Allow { - if resp.Error != nil { - return resp.Error - } return ErrWebhookDenied } wc.TemplateData.SetWebhook(wh.Name, resp.Data) @@ -104,9 +101,6 @@ func (wc *WebhookController) Authorize(ctx context.Context, req *webhook.Request return err } if !resp.Allow { - if resp.Error != nil { - return resp.Error - } return ErrWebhookDenied } } diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/wire/dpop_options.go b/vendor/github.com/smallstep/certificates/authority/provisioner/wire/dpop_options.go deleted file mode 100644 index 010cd5e..0000000 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/wire/dpop_options.go +++ /dev/null @@ -1,49 +0,0 @@ -package wire - -import ( - "bytes" - "crypto" - "errors" - "fmt" - "text/template" - - "go.step.sm/crypto/pemutil" -) - -type DPOPOptions struct { - // Public part of the signing key for DPoP access token in PEM format - SigningKey []byte `json:"key"` - // URI template for the URI the ACME client must call to fetch the DPoP challenge proof (an access token from wire-server) - Target string `json:"target"` - - signingKey crypto.PublicKey - target *template.Template -} - -func (o *DPOPOptions) GetSigningKey() crypto.PublicKey { - return o.signingKey -} - -func (o *DPOPOptions) EvaluateTarget(deviceID string) (string, error) { - if deviceID == "" { - return "", errors.New("deviceID must not be empty") - } - buf := new(bytes.Buffer) - if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil { - return "", fmt.Errorf("failed executing DPoP template: %w", err) - } - return buf.String(), nil -} - -func (o *DPOPOptions) validateAndInitialize() (err error) { - o.signingKey, err = pemutil.Parse(o.SigningKey) - if err != nil { - return fmt.Errorf("failed parsing key: %w", err) - } - o.target, err = template.New("DeviceID").Parse(o.Target) - if err != nil { - return fmt.Errorf("failed parsing DPoP template: %w", err) - } - - return nil -} diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/wire/oidc_options.go b/vendor/github.com/smallstep/certificates/authority/provisioner/wire/oidc_options.go deleted file mode 100644 index e9139ca..0000000 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/wire/oidc_options.go +++ /dev/null @@ -1,179 +0,0 @@ -package wire - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "net/url" - "text/template" - "time" - - "github.com/coreos/go-oidc/v3/oidc" - "go.step.sm/crypto/x509util" -) - -type Provider struct { - DiscoveryBaseURL string `json:"discoveryBaseUrl,omitempty"` - IssuerURL string `json:"issuerUrl,omitempty"` - AuthURL string `json:"authorizationUrl,omitempty"` - TokenURL string `json:"tokenUrl,omitempty"` - JWKSURL string `json:"jwksUrl,omitempty"` - UserInfoURL string `json:"userInfoUrl,omitempty"` - Algorithms []string `json:"signatureAlgorithms,omitempty"` -} - -type Config struct { - ClientID string `json:"clientId,omitempty"` - SignatureAlgorithms []string `json:"signatureAlgorithms,omitempty"` - - // the properties below are only used for testing - SkipClientIDCheck bool `json:"-"` - SkipExpiryCheck bool `json:"-"` - SkipIssuerCheck bool `json:"-"` - InsecureSkipSignatureCheck bool `json:"-"` - Now func() time.Time `json:"-"` -} - -type OIDCOptions struct { - Provider *Provider `json:"provider,omitempty"` - Config *Config `json:"config,omitempty"` - TransformTemplate string `json:"transform,omitempty"` - - target *template.Template - transform *template.Template - oidcProviderConfig *oidc.ProviderConfig - provider *oidc.Provider - verifier *oidc.IDTokenVerifier -} - -func (o *OIDCOptions) GetVerifier(ctx context.Context) (*oidc.IDTokenVerifier, error) { - if o.verifier == nil { - switch { - case o.Provider.DiscoveryBaseURL != "": - // creates a new OIDC provider using automatic discovery and the default HTTP client - provider, err := oidc.NewProvider(ctx, o.Provider.DiscoveryBaseURL) - if err != nil { - return nil, fmt.Errorf("failed creating new OIDC provider using discovery: %w", err) - } - o.provider = provider - default: - o.provider = o.oidcProviderConfig.NewProvider(ctx) - } - - if o.provider == nil { - return nil, errors.New("no OIDC provider available") - } - - o.verifier = o.provider.Verifier(o.getConfig()) - } - - return o.verifier, nil -} - -func (o *OIDCOptions) getConfig() *oidc.Config { - if o == nil || o.Config == nil { - return &oidc.Config{} - } - - return &oidc.Config{ - ClientID: o.Config.ClientID, - SupportedSigningAlgs: o.Config.SignatureAlgorithms, - SkipClientIDCheck: o.Config.SkipClientIDCheck, - SkipExpiryCheck: o.Config.SkipExpiryCheck, - SkipIssuerCheck: o.Config.SkipIssuerCheck, - Now: o.Config.Now, - InsecureSkipSignatureCheck: o.Config.InsecureSkipSignatureCheck, - } -} - -const defaultTemplate = `{"name": "{{ .name }}", "preferred_username": "{{ .preferred_username }}"}` - -func (o *OIDCOptions) validateAndInitialize() (err error) { - if o.Provider == nil { - return errors.New("provider not set") - } - if o.Provider.IssuerURL == "" && o.Provider.DiscoveryBaseURL == "" { - return errors.New("either OIDC discovery or issuer URL must be set") - } - - if o.Provider.DiscoveryBaseURL == "" { - o.oidcProviderConfig, err = toOIDCProviderConfig(o.Provider) - if err != nil { - return fmt.Errorf("failed creationg OIDC provider config: %w", err) - } - } - - o.target, err = template.New("DeviceID").Parse(o.Provider.IssuerURL) - if err != nil { - return fmt.Errorf("failed parsing OIDC template: %w", err) - } - - o.transform, err = parseTransform(o.TransformTemplate) - if err != nil { - return fmt.Errorf("failed parsing OIDC transformation template: %w", err) - } - - return nil -} - -func parseTransform(transformTemplate string) (*template.Template, error) { - if transformTemplate == "" { - transformTemplate = defaultTemplate - } - - return template.New("transform").Funcs(x509util.GetFuncMap()).Parse(transformTemplate) -} - -func (o *OIDCOptions) EvaluateTarget(deviceID string) (string, error) { - buf := new(bytes.Buffer) - if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil { - return "", fmt.Errorf("failed executing OIDC template: %w", err) - } - return buf.String(), nil -} - -func (o *OIDCOptions) Transform(v map[string]any) (map[string]any, error) { - if o.transform == nil || v == nil { - return v, nil - } - // TODO(hs): add support for extracting error message from template "fail" function? - buf := new(bytes.Buffer) - if err := o.transform.Execute(buf, v); err != nil { - return nil, fmt.Errorf("failed executing OIDC transformation: %w", err) - } - var r map[string]any - if err := json.Unmarshal(buf.Bytes(), &r); err != nil { - return nil, fmt.Errorf("failed unmarshaling transformed OIDC token: %w", err) - } - // add original claims if not yet in the transformed result - for key, value := range v { - if _, ok := r[key]; !ok { - r[key] = value - } - } - return r, nil -} - -func toOIDCProviderConfig(in *Provider) (*oidc.ProviderConfig, error) { - issuerURL, err := url.Parse(in.IssuerURL) - if err != nil { - return nil, fmt.Errorf("failed parsing issuer URL: %w", err) - } - // Removes query params from the URL because we use it as a way to notify client about the actual OAuth ClientId - // for this provisioner. - // This URL is going to look like: "https://idp:5556/dex?clientid=foo" - // If we don't trim the query params here i.e. 'clientid' then the idToken verification is going to fail because - // the 'iss' claim of the idToken will be "https://idp:5556/dex" - issuerURL.RawQuery = "" - issuerURL.Fragment = "" - return &oidc.ProviderConfig{ - IssuerURL: issuerURL.String(), - AuthURL: in.AuthURL, - TokenURL: in.TokenURL, - UserInfoURL: in.UserInfoURL, - JWKSURL: in.JWKSURL, - Algorithms: in.Algorithms, - }, nil -} diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/wire/wire_options.go b/vendor/github.com/smallstep/certificates/authority/provisioner/wire/wire_options.go deleted file mode 100644 index 2ae5543..0000000 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/wire/wire_options.go +++ /dev/null @@ -1,51 +0,0 @@ -package wire - -import ( - "errors" - "fmt" -) - -// Options holds the Wire ACME extension options -type Options struct { - OIDC *OIDCOptions `json:"oidc,omitempty"` - DPOP *DPOPOptions `json:"dpop,omitempty"` -} - -// GetOIDCOptions returns the OIDC options. -func (o *Options) GetOIDCOptions() *OIDCOptions { - if o == nil { - return nil - } - return o.OIDC -} - -// GetDPOPOptions returns the DPoP options. -func (o *Options) GetDPOPOptions() *DPOPOptions { - if o == nil { - return nil - } - return o.DPOP -} - -// Validate validates and initializes the Wire OIDC and DPoP options. -// -// TODO(hs): find a good way to perform this only once. -func (o *Options) Validate() error { - if oidc := o.GetOIDCOptions(); oidc != nil { - if err := oidc.validateAndInitialize(); err != nil { - return fmt.Errorf("failed initializing OIDC options: %w", err) - } - } else { - return errors.New("no OIDC options available") - } - - if dpop := o.GetDPOPOptions(); dpop != nil { - if err := dpop.validateAndInitialize(); err != nil { - return fmt.Errorf("failed initializing DPoP options: %w", err) - } - } else { - return errors.New("no DPoP options available") - } - - return nil -} diff --git a/vendor/github.com/smallstep/certificates/authority/provisioner/x5c.go b/vendor/github.com/smallstep/certificates/authority/provisioner/x5c.go index e1a152f..9b1f2b0 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioner/x5c.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioner/x5c.go @@ -21,10 +21,9 @@ import ( // x5cPayload extends jwt.Claims with step attributes. type x5cPayload struct { jose.Claims - SANs []string `json:"sans,omitempty"` - Step *stepPayload `json:"step,omitempty"` - Confirmation *cnfPayload `json:"cnf,omitempty"` - chains [][]*x509.Certificate + SANs []string `json:"sans,omitempty"` + Step *stepPayload `json:"step,omitempty"` + chains [][]*x509.Certificate } // X5C is the default provisioner, an entity that can sign tokens necessary for @@ -234,12 +233,6 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er } } - // Check the fingerprint of the certificate request if given. - var fingerprint string - if claims.Confirmation != nil { - fingerprint = claims.Confirmation.Fingerprint - } - return []SignOption{ self, templateOptions, @@ -250,7 +243,6 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er x5cLeaf.NotBefore, x5cLeaf.NotAfter, }, // validators - csrFingerprintValidator(fingerprint), commonNameValidator(claims.Subject), newDefaultSANsValidator(ctx, claims.SANs), defaultPublicKeyValidator{}, @@ -301,7 +293,7 @@ func (p *X5C) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e // Use options in the token. if opts.CertType != "" { if certType, err = sshutil.CertTypeFromString(opts.CertType); err != nil { - return nil, errs.BadRequestErr(err, err.Error()) //nolint:govet // allow non-constant error messages + return nil, errs.BadRequestErr(err, err.Error()) } } if opts.KeyID != "" { diff --git a/vendor/github.com/smallstep/certificates/authority/provisioners.go b/vendor/github.com/smallstep/certificates/authority/provisioners.go index 390a318..1502ea2 100644 --- a/vendor/github.com/smallstep/certificates/authority/provisioners.go +++ b/vendor/github.com/smallstep/certificates/authority/provisioners.go @@ -11,8 +11,8 @@ import ( "github.com/pkg/errors" - "github.com/smallstep/cli-utils/step" - "github.com/smallstep/cli-utils/ui" + "go.step.sm/cli-utils/step" + "go.step.sm/cli-utils/ui" "go.step.sm/crypto/jose" "go.step.sm/linkedca" @@ -201,7 +201,6 @@ func (a *Authority) generateProvisionerConfig(ctx context.Context) (provisioner. AuthorizeRenewFunc: a.authorizeRenewFunc, AuthorizeSSHRenewFunc: a.authorizeSSHRenewFunc, WebhookClient: a.webhookClient, - HTTPClient: a.httpClient, SCEPKeyManager: a.scepKeyManager, }, nil } @@ -427,25 +426,25 @@ func ValidateClaims(c *linkedca.Claims) error { // ValidateDurations validates the Durations type. func ValidateDurations(d *linkedca.Durations) error { var ( - err error - minDur, maxDur, def *provisioner.Duration + err error + min, max, def *provisioner.Duration ) if d.Min != "" { - minDur, err = provisioner.NewDuration(d.Min) + min, err = provisioner.NewDuration(d.Min) if err != nil { return admin.WrapError(admin.ErrorBadRequestType, err, "min duration '%s' is invalid", d.Min) } - if minDur.Value() < 0 { + if min.Value() < 0 { return admin.WrapError(admin.ErrorBadRequestType, err, "min duration '%s' cannot be less than 0", d.Min) } } if d.Max != "" { - maxDur, err = provisioner.NewDuration(d.Max) + max, err = provisioner.NewDuration(d.Max) if err != nil { return admin.WrapError(admin.ErrorBadRequestType, err, "max duration '%s' is invalid", d.Max) } - if maxDur.Value() < 0 { + if max.Value() < 0 { return admin.WrapError(admin.ErrorBadRequestType, err, "max duration '%s' cannot be less than 0", d.Max) } } @@ -458,15 +457,15 @@ func ValidateDurations(d *linkedca.Durations) error { return admin.WrapError(admin.ErrorBadRequestType, err, "default duration '%s' cannot be less than 0", d.Default) } } - if d.Min != "" && d.Max != "" && minDur.Value() > maxDur.Value() { + if d.Min != "" && d.Max != "" && min.Value() > max.Value() { return admin.NewError(admin.ErrorBadRequestType, "min duration '%s' cannot be greater than max duration '%s'", d.Min, d.Max) } - if d.Min != "" && d.Default != "" && minDur.Value() > def.Value() { + if d.Min != "" && d.Default != "" && min.Value() > def.Value() { return admin.NewError(admin.ErrorBadRequestType, "min duration '%s' cannot be greater than default duration '%s'", d.Min, d.Default) } - if d.Default != "" && d.Max != "" && minDur.Value() > def.Value() { + if d.Default != "" && d.Max != "" && min.Value() > def.Value() { return admin.NewError(admin.ErrorBadRequestType, "default duration '%s' cannot be greater than max duration '%s'", d.Default, d.Max) } @@ -609,15 +608,15 @@ func provisionerWebhookToLinkedca(pwh *provisioner.Webhook) *linkedca.Webhook { return lwh } -func durationsToCertificates(d *linkedca.Durations) (minDur, maxDur, def *provisioner.Duration, err error) { +func durationsToCertificates(d *linkedca.Durations) (min, max, def *provisioner.Duration, err error) { if d.Min != "" { - minDur, err = provisioner.NewDuration(d.Min) + min, err = provisioner.NewDuration(d.Min) if err != nil { return nil, nil, nil, admin.WrapErrorISE(err, "error parsing minimum duration '%s'", d.Min) } } if d.Max != "" { - maxDur, err = provisioner.NewDuration(d.Max) + max, err = provisioner.NewDuration(d.Max) if err != nil { return nil, nil, nil, admin.WrapErrorISE(err, "error parsing maximum duration '%s'", d.Max) } @@ -919,8 +918,6 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, Domains: cfg.Domains, Groups: cfg.Groups, ListenAddress: cfg.ListenAddress, - Scopes: cfg.Scopes, - AuthParams: cfg.AuthParams, Claims: claims, Options: options, }, nil @@ -955,8 +952,6 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, ProjectIDs: cfg.ProjectIds, DisableCustomSANs: cfg.DisableCustomSans, DisableTrustOnFirstUse: cfg.DisableTrustOnFirstUse, - DisableSSHCAUser: cfg.DisableSshCaUser, - DisableSSHCAHost: cfg.DisableSshCaHost, InstanceAge: instanceAge, Claims: claims, Options: options, @@ -1071,8 +1066,6 @@ func ProvisionerToLinkedca(p provisioner.Interface) (*linkedca.Provisioner, erro Groups: p.Groups, ListenAddress: p.ListenAddress, TenantId: p.TenantID, - Scopes: p.Scopes, - AuthParams: p.AuthParams, }, }, }, @@ -1097,8 +1090,6 @@ func ProvisionerToLinkedca(p provisioner.Interface) (*linkedca.Provisioner, erro ProjectIds: p.ProjectIDs, DisableCustomSans: p.DisableCustomSANs, DisableTrustOnFirstUse: p.DisableTrustOnFirstUse, - DisableSshCaUser: p.DisableSSHCAUser, - DisableSshCaHost: p.DisableSSHCAHost, InstanceAge: p.InstanceAge.String(), }, }, diff --git a/vendor/github.com/smallstep/certificates/authority/root.go b/vendor/github.com/smallstep/certificates/authority/root.go index 0a6ee63..37038cf 100644 --- a/vendor/github.com/smallstep/certificates/authority/root.go +++ b/vendor/github.com/smallstep/certificates/authority/root.go @@ -57,26 +57,3 @@ func (a *Authority) GetFederation() (federation []*x509.Certificate, err error) }) return } - -// GetIntermediateCertificate return the intermediate certificate that issues -// the leaf certificates in the CA. -// -// This method can return nil if the CA is configured with a Certificate -// Authority Service (CAS) that does not implement the -// CertificateAuthorityGetter interface. -func (a *Authority) GetIntermediateCertificate() *x509.Certificate { - if len(a.intermediateX509Certs) > 0 { - return a.intermediateX509Certs[0] - } - return nil -} - -// GetIntermediateCertificates returns a list of all intermediate certificates -// configured. The first certificate in the list will be the issuer certificate. -// -// This method can return an empty list or nil if the CA is configured with a -// Certificate Authority Service (CAS) that does not implement the -// CertificateAuthorityGetter interface. -func (a *Authority) GetIntermediateCertificates() []*x509.Certificate { - return a.intermediateX509Certs -} diff --git a/vendor/github.com/smallstep/certificates/authority/ssh.go b/vendor/github.com/smallstep/certificates/authority/ssh.go index b28aa15..55f4f4a 100644 --- a/vendor/github.com/smallstep/certificates/authority/ssh.go +++ b/vendor/github.com/smallstep/certificates/authority/ssh.go @@ -154,16 +154,12 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, provisioner.Interface, error) { var ( - certOptions []sshutil.Option - mods []provisioner.SSHCertModifier - validators []provisioner.SSHCertValidator - keyValidators []provisioner.SSHPublicKeyValidator + certOptions []sshutil.Option + mods []provisioner.SSHCertModifier + validators []provisioner.SSHCertValidator ) - // Validate given key and options - if key == nil { - return nil, nil, errs.BadRequest("ssh public key cannot be nil") - } + // Validate given options. if err := opts.Validate(); err != nil { return nil, nil, err } @@ -187,10 +183,6 @@ func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisi case provisioner.SSHCertModifier: mods = append(mods, o) - // validate the ssh public key - case provisioner.SSHPublicKeyValidator: - keyValidators = append(keyValidators, o) - // validate the ssh.Certificate case provisioner.SSHCertValidator: validators = append(validators, o) @@ -210,16 +202,6 @@ func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisi } } - // Validate public key - for _, v := range keyValidators { - if err := v.Valid(key); err != nil { - return nil, nil, errs.ApplyOptions( - errs.ForbiddenErr(err, err.Error()), //nolint:govet // allow non-constant error messages - errs.WithKeyVal("signOptions", signOpts), - ) - } - } - // Simulated certificate request with request options. cr := sshutil.CertificateRequest{ Type: opts.CertType, @@ -231,7 +213,7 @@ func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisi // Call enriching webhooks if err := a.callEnrichingWebhooksSSH(ctx, prov, webhookCtl, cr); err != nil { return nil, prov, errs.ApplyOptions( - errs.ForbiddenErr(err, err.Error()), //nolint:govet // allow non-constant error messages + errs.ForbiddenErr(err, err.Error()), errs.WithKeyVal("signOptions", signOpts), ) } @@ -243,7 +225,7 @@ func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisi switch { case errors.As(err, &te): return nil, prov, errs.ApplyOptions( - errs.BadRequestErr(err, err.Error()), //nolint:govet // allow non-constant error messages + errs.BadRequestErr(err, err.Error()), errs.WithKeyVal("signOptions", signOpts), ) case strings.HasPrefix(err.Error(), "error unmarshaling certificate"): @@ -263,7 +245,7 @@ func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisi // Use SignSSHOptions to modify the certificate validity. It will be later // checked or set if not defined. if err := opts.ModifyValidity(certTpl); err != nil { - return nil, prov, errs.BadRequestErr(err, err.Error()) //nolint:govet // allow non-constant error messages + return nil, prov, errs.BadRequestErr(err, err.Error()) } // Use provisioner modifiers. diff --git a/vendor/github.com/smallstep/certificates/authority/tls.go b/vendor/github.com/smallstep/certificates/authority/tls.go index 320eb59..ebc9d0d 100644 --- a/vendor/github.com/smallstep/certificates/authority/tls.go +++ b/vendor/github.com/smallstep/certificates/authority/tls.go @@ -91,21 +91,6 @@ func withDefaultASN1DN(def *config.ASN1DN) provisioner.CertificateModifierFunc { } } -// GetX509Signer returns a [crypto.Signer] implementation using the intermediate -// key. -// -// This method can return a [NotImplementedError] if the CA is configured with a -// Certificate Authority Service (CAS) that does not implement the -// CertificateAuthoritySigner interface. -// -// [NotImplementedError]: https://pkg.go.dev/github.com/smallstep/certificates/cas/apiv1#NotImplementedError -func (a *Authority) GetX509Signer() (crypto.Signer, error) { - if s, ok := a.x509CAService.(casapi.CertificateAuthoritySigner); ok { - return s.GetSigner() - } - return nil, casapi.NotImplementedError{} -} - // Sign creates a signed certificate from a certificate signing request. It // creates a new context.Context, and calls into SignWithContext. // @@ -197,7 +182,7 @@ func (a *Authority) signX509(ctx context.Context, csr *x509.CertificateRequest, if err := a.callEnrichingWebhooksX509(ctx, prov, webhookCtl, attData, csr); err != nil { return nil, prov, errs.ApplyOptions( - errs.ForbiddenErr(err, err.Error()), //nolint:govet // allow non-constant error messages + errs.ForbiddenErr(err, err.Error()), errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts), ) @@ -209,7 +194,7 @@ func (a *Authority) signX509(ctx context.Context, csr *x509.CertificateRequest, switch { case errors.As(err, &te): return nil, prov, errs.ApplyOptions( - errs.BadRequestErr(err, err.Error()), //nolint:govet // allow non-constant error messages + errs.BadRequestErr(err, err.Error()), errs.WithKeyVal("csr", csr), errs.WithKeyVal("signOptions", signOpts), ) diff --git a/vendor/github.com/smallstep/certificates/cas/apiv1/services.go b/vendor/github.com/smallstep/certificates/cas/apiv1/services.go index 37c5adb..00ecc2a 100644 --- a/vendor/github.com/smallstep/certificates/cas/apiv1/services.go +++ b/vendor/github.com/smallstep/certificates/cas/apiv1/services.go @@ -1,7 +1,6 @@ package apiv1 import ( - "crypto" "crypto/x509" "net/http" "strings" @@ -27,20 +26,13 @@ type CertificateAuthorityGetter interface { GetCertificateAuthority(req *GetCertificateAuthorityRequest) (*GetCertificateAuthorityResponse, error) } -// CertificateAuthorityCreator is an interface implemented by a +// CertificateAuthorityCreator is an interface implamented by a // CertificateAuthorityService that has a method to create a new certificate // authority. type CertificateAuthorityCreator interface { CreateCertificateAuthority(req *CreateCertificateAuthorityRequest) (*CreateCertificateAuthorityResponse, error) } -// CertificateAuthoritySigner is an optional interface implemented by a -// CertificateAuthorityService that has a method that returns a [crypto.Signer] -// using the same key used to issue certificates. -type CertificateAuthoritySigner interface { - GetSigner() (crypto.Signer, error) -} - // SignatureAlgorithmGetter is an optional implementation in a crypto.Signer // that returns the SignatureAlgorithm to use. type SignatureAlgorithmGetter interface { diff --git a/vendor/github.com/smallstep/certificates/cas/softcas/softcas.go b/vendor/github.com/smallstep/certificates/cas/softcas/softcas.go index 1e590ef..dd96197 100644 --- a/vendor/github.com/smallstep/certificates/cas/softcas/softcas.go +++ b/vendor/github.com/smallstep/certificates/cas/softcas/softcas.go @@ -58,13 +58,6 @@ func (c *SoftCAS) Type() apiv1.Type { return apiv1.SoftCAS } -// GetSigner implements [apiv1.CertificateAuthoritySigner] and returns a -// [crypto.Signer] with the intermediate key. -func (c *SoftCAS) GetSigner() (crypto.Signer, error) { - _, signer, err := c.getCertSigner() - return signer, err -} - // CreateCertificate signs a new certificate using Golang or KMS crypto. func (c *SoftCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1.CreateCertificateResponse, error) { switch { diff --git a/vendor/github.com/smallstep/certificates/errs/error.go b/vendor/github.com/smallstep/certificates/errs/error.go index f01cb4d..4ea5001 100644 --- a/vendor/github.com/smallstep/certificates/errs/error.go +++ b/vendor/github.com/smallstep/certificates/errs/error.go @@ -62,11 +62,6 @@ type ErrorResponse struct { Message string `json:"message"` } -// Unwrap implements the Unwrap interface and returns the original error. -func (e *Error) Unwrap() error { - return e.Err -} - // Cause implements the errors.Causer interface and returns the original error. func (e *Error) Cause() error { return e.Err @@ -182,7 +177,7 @@ func StatusCodeError(code int, e error, opts ...Option) error { } } -const ( +var ( seeLogs = "Please see the certificate authority logs for more info." // BadRequestDefaultMsg 400 default msg BadRequestDefaultMsg = "The request could not be completed; malformed or missing data. " + seeLogs @@ -198,7 +193,7 @@ const ( NotImplementedDefaultMsg = "The requested method is not implemented by the certificate authority. " + seeLogs ) -const ( +var ( // BadRequestPrefix is the prefix added to the bad request messages that are // directly sent to the cli. BadRequestPrefix = "The request could not be completed: " diff --git a/vendor/github.com/smallstep/certificates/logging/handler.go b/vendor/github.com/smallstep/certificates/logging/handler.go index e9823c6..701d631 100644 --- a/vendor/github.com/smallstep/certificates/logging/handler.go +++ b/vendor/github.com/smallstep/certificates/logging/handler.go @@ -14,14 +14,6 @@ import ( "github.com/smallstep/certificates/middleware/requestid" ) -// Common headers used for identifying the originating IP address of a client -// connecting to a web server through a proxy server -var ( - trueClientIP = http.CanonicalHeaderKey("True-Client-IP") - xRealIP = http.CanonicalHeaderKey("X-Real-IP") - xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For") -) - // LoggerHandler creates a logger handler type LoggerHandler struct { name string @@ -36,23 +28,16 @@ type options struct { // endpoint should only be logged at the TRACE level in the (expected) HTTP // 200 case onlyTraceHealthEndpoint bool - - // logRealIP determines if the real IP address of the client should be logged - // instead of the IP address of the proxy - logRealIP bool } // NewLoggerHandler returns the given http.Handler with the logger integrated. func NewLoggerHandler(name string, logger *Logger, next http.Handler) http.Handler { onlyTraceHealthEndpoint, _ := strconv.ParseBool(os.Getenv("STEP_LOGGER_ONLY_TRACE_HEALTH_ENDPOINT")) - logRealIP, _ := strconv.ParseBool(os.Getenv("STEP_LOGGER_LOG_REAL_IP")) - return &LoggerHandler{ name: name, logger: logger.GetImpl(), options: options{ onlyTraceHealthEndpoint: onlyTraceHealthEndpoint, - logRealIP: logRealIP, }, next: next, } @@ -82,12 +67,9 @@ func (l *LoggerHandler) writeEntry(w ResponseLogger, r *http.Request, t time.Tim } // Remote hostname - addr := r.RemoteAddr - if l.options.logRealIP { - addr = realIP(r) - } - if host, _, err := net.SplitHostPort(addr); err == nil { - addr = host + addr, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + addr = r.RemoteAddr } // From https://github.com/gorilla/handlers @@ -143,27 +125,3 @@ func sanitizeLogEntry(s string) string { escaped := strings.ReplaceAll(s, "\n", "") return strings.ReplaceAll(escaped, "\r", "") } - -// realIP returns the real IP address of the client connecting to the server by -// parsing either the True-Client-IP, X-Real-IP or the X-Forwarded-For headers -// (in that order). If the headers are not set or set to an invalid IP, it -// returns the RemoteAddr of the request. -func realIP(r *http.Request) string { - var ip string - - if tcip := r.Header.Get(trueClientIP); tcip != "" { - ip = tcip - } else if xrip := r.Header.Get(xRealIP); xrip != "" { - ip = xrip - } else if xff := r.Header.Get(xForwardedFor); xff != "" { - i := strings.Index(xff, ",") - if i == -1 { - i = len(xff) - } - ip = xff[:i] - } - if ip == "" || net.ParseIP(ip) == nil { - return r.RemoteAddr - } - return ip -} diff --git a/vendor/github.com/smallstep/certificates/policy/engine.go b/vendor/github.com/smallstep/certificates/policy/engine.go index 0f9af0d..5645732 100644 --- a/vendor/github.com/smallstep/certificates/policy/engine.go +++ b/vendor/github.com/smallstep/certificates/policy/engine.go @@ -270,7 +270,7 @@ func (e *NamePolicyEngine) IsSSHCertificateAllowed(cert *ssh.Certificate) error return e.validateNames(dnsNames, ips, emails, []*url.URL{}, principals) } -// splitSSHPrincipals splits SSH certificate principals into DNS names, emails and usernames. +// splitPrincipals splits SSH certificate principals into DNS names, emails and usernames. func splitSSHPrincipals(cert *ssh.Certificate) (dnsNames []string, ips []net.IP, emails, principals []string, err error) { dnsNames = []string{} ips = []net.IP{} diff --git a/vendor/github.com/smallstep/certificates/scep/authority.go b/vendor/github.com/smallstep/certificates/scep/authority.go index 256c540..00c58d8 100644 --- a/vendor/github.com/smallstep/certificates/scep/authority.go +++ b/vendor/github.com/smallstep/certificates/scep/authority.go @@ -241,7 +241,7 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err // SignCSR creates an x509.Certificate based on a CSR template and Cert Authority credentials // returns a new PKIMessage with CertRep data -func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage, signCSROpts ...provisioner.SignCSROption) (*PKIMessage, error) { +func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage) (*PKIMessage, error) { // TODO: intermediate storage of the request? In SCEP it's possible to request a csr/certificate // to be signed, which can be performed asynchronously / out-of-band. In that case a client can // poll for the status. It seems to be similar as what can happen in ACME, so might want to model @@ -284,13 +284,6 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m CommonName: csr.Subject.CommonName, }) - // Apply CSR options. Currently only one option is defined. - for _, o := range signCSROpts { - if m, ok := o.(provisioner.TemplateDataModifier); ok { - m.Modify(data) - } - } - // Get authorizations from the SCEP provisioner. ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod) signOps, err := p.AuthorizeSign(ctx, "") @@ -513,7 +506,7 @@ func (a *Authority) GetCACaps(ctx context.Context) []string { return caps } -func (a *Authority) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) ([]provisioner.SignCSROption, error) { +func (a *Authority) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error { p := provisionerFromContext(ctx) return p.ValidateChallenge(ctx, csr, challenge, transactionID) } diff --git a/vendor/github.com/smallstep/certificates/scep/provisioner.go b/vendor/github.com/smallstep/certificates/scep/provisioner.go index 35821d8..3df4b36 100644 --- a/vendor/github.com/smallstep/certificates/scep/provisioner.go +++ b/vendor/github.com/smallstep/certificates/scep/provisioner.go @@ -20,7 +20,7 @@ type Provisioner interface { GetDecrypter() (*x509.Certificate, crypto.Decrypter) GetSigner() (*x509.Certificate, crypto.Signer) GetContentEncryptionAlgorithm() int - ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) ([]provisioner.SignCSROption, error) + ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error NotifySuccess(ctx context.Context, csr *x509.CertificateRequest, cert *x509.Certificate, transactionID string) error NotifyFailure(ctx context.Context, csr *x509.CertificateRequest, transactionID string, errorCode int, errorDescription string) error } diff --git a/vendor/github.com/smallstep/certificates/scep/scep.go b/vendor/github.com/smallstep/certificates/scep/scep.go index ec7fd05..da7e202 100644 --- a/vendor/github.com/smallstep/certificates/scep/scep.go +++ b/vendor/github.com/smallstep/certificates/scep/scep.go @@ -9,15 +9,6 @@ import ( smallscep "github.com/smallstep/scep" ) -func init() { - // enable the fallback X509 certificate parser to support parsing - // Windows SCEP enrollment certificates that contain a critical - // authority key identifier extension. Starting with Go 1.23 those - // fail to be parsed by crypto/x509. Enabling the legacy fallback - // parser is a workaround for that. - pkcs7.SetFallbackLegacyX509CertificateParserEnabled(true) -} - // FailInfoName models the name/value of failInfo type FailInfoName smallscep.FailInfo diff --git a/vendor/github.com/smallstep/certificates/templates/templates.go b/vendor/github.com/smallstep/certificates/templates/templates.go index e58f5fb..2544b6e 100644 --- a/vendor/github.com/smallstep/certificates/templates/templates.go +++ b/vendor/github.com/smallstep/certificates/templates/templates.go @@ -9,9 +9,8 @@ import ( "github.com/Masterminds/sprig/v3" "github.com/pkg/errors" - - "github.com/smallstep/cli-utils/fileutil" - "github.com/smallstep/cli-utils/step" + "go.step.sm/cli-utils/fileutil" + "go.step.sm/cli-utils/step" ) // TemplateType defines how a template will be written in disk. diff --git a/vendor/github.com/smallstep/certificates/templates/values.go b/vendor/github.com/smallstep/certificates/templates/values.go index f02ba47..aa158a9 100644 --- a/vendor/github.com/smallstep/certificates/templates/values.go +++ b/vendor/github.com/smallstep/certificates/templates/values.go @@ -108,10 +108,10 @@ var DefaultSSHTemplateData = map[string]string{ {{- end }} {{- if or .User.GOOS "none" | eq "windows" }} UserKnownHostsFile "{{.User.StepPath}}\ssh\known_hosts" - ProxyCommand C:\Windows\System32\cmd.exe /c step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }}{{- if .User.Console}} --console {{- end }}{{- if .User.Provisioner }} --provisioner {{ .User.Provisioner }}{{- end }} %r %h %p + ProxyCommand C:\Windows\System32\cmd.exe /c step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }}{{- if .User.Provisioner }} --provisioner {{ .User.Provisioner }}{{- end }} %r %h %p {{- else }} UserKnownHostsFile "{{.User.StepPath}}/ssh/known_hosts" - ProxyCommand step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }}{{- if .User.Console}} --console {{- end }}{{- if .User.Provisioner }} --provisioner {{ .User.Provisioner }}{{- end }} %r %h %p + ProxyCommand step ssh proxycommand{{- if .User.Context }} --context {{ .User.Context }}{{- end }}{{- if .User.Provisioner }} --provisioner {{ .User.Provisioner }}{{- end }} %r %h %p {{- end }} `, diff --git a/vendor/github.com/smallstep/certificates/webhook/types.go b/vendor/github.com/smallstep/certificates/webhook/types.go index c60de70..5e0e4d2 100644 --- a/vendor/github.com/smallstep/certificates/webhook/types.go +++ b/vendor/github.com/smallstep/certificates/webhook/types.go @@ -1,7 +1,6 @@ package webhook import ( - "fmt" "time" "go.step.sm/crypto/sshutil" @@ -10,19 +9,8 @@ import ( // ResponseBody is the body returned by webhook servers. type ResponseBody struct { - Data any `json:"data"` - Allow bool `json:"allow"` - Error *Error `json:"error,omitempty"` -} - -// Error provides details explaining why the webhook was not permitted. -type Error struct { - Code string `json:"code"` - Message string `json:"message"` -} - -func (e *Error) Error() string { - return fmt.Sprintf("%s (%s)", e.Message, e.Code) + Data any `json:"data"` + Allow bool `json:"allow"` } // X509CertificateRequest is the certificate request sent to webhook servers for diff --git a/vendor/github.com/smallstep/cli-utils/LICENSE b/vendor/github.com/smallstep/cli-utils/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/vendor/github.com/smallstep/cli-utils/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/smallstep/cli-utils/command/command.go b/vendor/github.com/smallstep/cli-utils/command/command.go deleted file mode 100644 index 5da6e85..0000000 --- a/vendor/github.com/smallstep/cli-utils/command/command.go +++ /dev/null @@ -1,45 +0,0 @@ -package command - -import ( - "os" - - "github.com/urfave/cli" - - "github.com/smallstep/cli-utils/step" - "github.com/smallstep/cli-utils/usage" -) - -var cmds []cli.Command -var currentContext *cli.Context - -func init() { - os.Unsetenv(step.IgnoreEnvVar) - cmds = []cli.Command{ - usage.HelpCommand(), - } -} - -// Register adds the given command to the global list of commands. -// It sets recursively the command Flags environment variables. -func Register(c cli.Command) { - step.SetEnvVar(&c) - cmds = append(cmds, c) -} - -// Retrieve returns all commands -func Retrieve() []cli.Command { - return cmds -} - -// ActionFunc returns a cli.ActionFunc that stores the context. -func ActionFunc(fn cli.ActionFunc) cli.ActionFunc { - return func(ctx *cli.Context) error { - currentContext = ctx - return fn(ctx) - } -} - -// IsForce returns if the force flag was passed -func IsForce() bool { - return currentContext != nil && currentContext.Bool("force") -} diff --git a/vendor/github.com/smallstep/cli-utils/errs/errs.go b/vendor/github.com/smallstep/cli-utils/errs/errs.go deleted file mode 100644 index 28ecf1e..0000000 --- a/vendor/github.com/smallstep/cli-utils/errs/errs.go +++ /dev/null @@ -1,330 +0,0 @@ -package errs - -import ( - "fmt" - "os" - "strings" - - "errors" - - pkge "github.com/pkg/errors" - "github.com/urfave/cli" -) - -// NewError returns a new Error for the given format and arguments -func NewError(format string, args ...interface{}) error { - return fmt.Errorf(format, args...) -} - -// NewExitError returns an error that the urfave/cli package will handle and -// will show the given error and exit with the given code. -func NewExitError(err error, exitCode int) error { - return cli.NewExitError(err, exitCode) -} - -// Wrap returns a new error wrapped by the given error with the given message. -// If the given error implements the errors.Cause interface, the base error is -// used. If the given error is wrapped by a package name, the error wrapped -// will be the string after the last colon. -// -// TODO: this should be refactored to use Go's wrap facilities. -func Wrap(err error, format string, args ...interface{}) error { - if err == nil { - return nil - } - cause := pkge.Cause(err) - if errors.Is(err, cause) { - str := err.Error() - if i := strings.LastIndexByte(str, ':'); i >= 0 { - str = strings.TrimSpace(str[i:]) - return pkge.Wrapf(errors.New(str), format, args...) - } - } - return pkge.Wrapf(cause, format, args...) -} - -// InsecureCommand returns an error with a message saying that the current -// command requires the insecure flag. -func InsecureCommand(ctx *cli.Context) error { - return fmt.Errorf("'%s %s' requires the '--insecure' flag", ctx.App.Name, ctx.Command.Name) -} - -// EqualArguments returns an error saying that the given positional arguments -// cannot be equal. -func EqualArguments(ctx *cli.Context, arg1, arg2 string) error { - return fmt.Errorf("positional arguments <%s> and <%s> cannot be equal in '%s'", arg1, arg2, usage(ctx)) -} - -// MissingArguments returns an error with a missing arguments message for the -// given positional argument names. -func MissingArguments(ctx *cli.Context, argNames ...string) error { - switch len(argNames) { - case 0: - return fmt.Errorf("missing positional arguments in '%s'", usage(ctx)) - case 1: - return fmt.Errorf("missing positional argument <%s> in '%s'", argNames[0], usage(ctx)) - default: - args := make([]string, len(argNames)) - for i, name := range argNames { - args[i] = "<" + name + ">" - } - return fmt.Errorf("missing positional arguments %s in '%s'", strings.Join(args, " "), usage(ctx)) - } -} - -// NumberOfArguments returns nil if the number of positional arguments is -// equal to the required one. It will return an appropriate error if they are -// not. -func NumberOfArguments(ctx *cli.Context, required int) error { - n := ctx.NArg() - switch { - case n < required: - return TooFewArguments(ctx) - case n > required: - return TooManyArguments(ctx) - default: - return nil - } -} - -// MinMaxNumberOfArguments returns nil if the number of positional arguments -// between the min/max range. It will return an appropriate error if they are -// not. -func MinMaxNumberOfArguments(ctx *cli.Context, minNumber, maxNumber int) error { - n := ctx.NArg() - switch { - case n < minNumber: - return TooFewArguments(ctx) - case n > maxNumber: - return TooManyArguments(ctx) - default: - return nil - } -} - -// TooFewArguments returns an error with a few arguments were provided message. -func TooFewArguments(ctx *cli.Context) error { - return fmt.Errorf("not enough positional arguments were provided in '%s'", usage(ctx)) -} - -// TooManyArguments returns an error with a too many arguments were provided -// message. -func TooManyArguments(ctx *cli.Context) error { - return fmt.Errorf("too many positional arguments were provided in '%s'", usage(ctx)) -} - -// InsecureArgument returns an error with the given argument requiring the -// --insecure flag. -func InsecureArgument(_ *cli.Context, name string) error { - return fmt.Errorf("positional argument <%s> requires the '--insecure' flag", name) -} - -// FlagValueInsecure returns an error with the given flag and value requiring -// the --insecure flag. -func FlagValueInsecure(_ *cli.Context, flag, value string) error { - return fmt.Errorf("flag '--%s %s' requires the '--insecure' flag", flag, value) -} - -// InvalidFlagValue returns an error with the given value being missing or -// invalid for the given flag. Optionally it lists the given formatted options -// at the end. -func InvalidFlagValue(ctx *cli.Context, flag, value, options string) error { - if options != "" { - options = fmt.Sprintf("options are %s", options) - } - - return InvalidFlagValueMsg(ctx, flag, value, options) -} - -// InvalidFlagValueMsg returns an error with the given value being missing or -// invalid for the given flag. Optionally it returns an error message to aid -// in debugging. -func InvalidFlagValueMsg(_ *cli.Context, flag, value, msg string) error { - var format string - if value == "" { - format = fmt.Sprintf("missing value for flag '--%s'", flag) - } else { - format = fmt.Sprintf("invalid value '%s' for flag '--%s'", value, flag) - } - - if msg == "" { - return errors.New(format) - } - - return errors.New(format + "; " + msg) -} - -// IncompatibleFlag returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlag(_ *cli.Context, flag, value string) error { - return fmt.Errorf("flag '--%s' is incompatible with '%s'", flag, value) -} - -// IncompatibleFlagWithFlag returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlagWithFlag(_ *cli.Context, flag, withFlag string) error { - return fmt.Errorf("flag '--%s' is incompatible with '--%s'", flag, withFlag) -} - -// IncompatibleFlagValue returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlagValue(_ *cli.Context, flag, incompatibleWith, - incompatibleWithValue string) error { - return fmt.Errorf("flag '--%s' is incompatible with flag '--%s %s'", - flag, incompatibleWith, incompatibleWithValue) -} - -// IncompatibleFlagValues returns an error with the flag being incompatible with the -// given value. -func IncompatibleFlagValues(ctx *cli.Context, flag, value, incompatibleWith, - incompatibleWithValue string) error { - return IncompatibleFlagValueWithFlagValue(ctx, flag, value, incompatibleWith, - incompatibleWithValue, "") -} - -// IncompatibleFlagValueWithFlagValue returns an error with the given value -// being missing or invalid for the given flag. Optionally it lists the given -// formatted options at the end. -func IncompatibleFlagValueWithFlagValue(_ *cli.Context, flag, value, - withFlag, withValue, options string) error { - format := fmt.Sprintf("flag '--%s %s' is incompatible with flag '--%s %s'", - flag, value, withFlag, withValue) - - if options == "" { - return errors.New(format) - } - - // TODO: check whether double space before options is intended - return fmt.Errorf("%s\n\n Option(s): --%s %s", format, withFlag, options) -} - -// RequiredFlag returns an error with the required flag message. -func RequiredFlag(ctx *cli.Context, flag string) error { - return fmt.Errorf("'%s %s' requires the '--%s' flag", ctx.App.HelpName, - ctx.Command.Name, flag) -} - -// RequiredWithFlag returns an error with the required flag message with another flag. -func RequiredWithFlag(_ *cli.Context, flag, required string) error { - return fmt.Errorf("flag '--%s' requires the '--%s' flag", flag, required) -} - -// RequiredWithFlagValue returns an error with the required flag message. -func RequiredWithFlagValue(_ *cli.Context, flag, value, required string) error { - return fmt.Errorf("'--%s %s' requires the '--%s' flag", flag, value, required) -} - -// RequiredWithProvisionerTypeFlag returns an error with the required flag message. -func RequiredWithProvisionerTypeFlag(_ *cli.Context, provisionerType, required string) error { - return fmt.Errorf("provisioner type '%s' requires the '--%s' flag", provisionerType, required) -} - -// RequiredInsecureFlag returns an error with the given flag requiring the -// insecure flag message. -func RequiredInsecureFlag(_ *cli.Context, flag string) error { - return fmt.Errorf("flag '--%s' requires the '--insecure' flag", flag) -} - -// RequiredSubtleFlag returns an error with the given flag requiring the -// subtle flag message.. -func RequiredSubtleFlag(_ *cli.Context, flag string) error { - return fmt.Errorf("flag '--%s' requires the '--subtle' flag", flag) -} - -// RequiredUnlessInsecureFlag returns an error with the required flag message unless -// the insecure flag is used. -func RequiredUnlessInsecureFlag(ctx *cli.Context, flag string) error { - return RequiredUnlessFlag(ctx, flag, "insecure") -} - -// RequiredUnlessFlag returns an error with the required flag message unless -// the specified flag is used. -func RequiredUnlessFlag(_ *cli.Context, flag, unlessFlag string) error { - return fmt.Errorf("flag '--%s' is required unless the '--%s' flag is provided", flag, unlessFlag) -} - -// RequiredUnlessSubtleFlag returns an error with the required flag message unless -// the subtle flag is used. -func RequiredUnlessSubtleFlag(ctx *cli.Context, flag string) error { - return RequiredUnlessFlag(ctx, flag, "subtle") -} - -// RequiredOrFlag returns an error with a list of flags being required messages. -func RequiredOrFlag(_ *cli.Context, flags ...string) error { - params := make([]string, len(flags)) - for i, flag := range flags { - params[i] = "--" + flag - } - return fmt.Errorf("one of flag %s is required", strings.Join(params, " or ")) -} - -// RequiredWithOrFlag returns an error with a list of flags at least one of which -// is required in conjunction with the last flag in the list. -func RequiredWithOrFlag(_ *cli.Context, withFlag string, flags ...string) error { - params := make([]string, len(flags)) - for i := 0; i < len(flags); i++ { - params[i] = "--" + flags[i] - } - return fmt.Errorf("one of flag %s is required with flag --%s", strings.Join(params, " or "), withFlag) -} - -// MinSizeFlag returns an error with a greater or equal message message for -// the given flag and size. -func MinSizeFlag(_ *cli.Context, flag, size string) error { - return fmt.Errorf("flag '--%s' must be greater than or equal to %s", flag, size) -} - -// MinSizeInsecureFlag returns an error with a requiring --insecure flag -// message with the given flag an size. -func MinSizeInsecureFlag(_ *cli.Context, flag, size string) error { - return fmt.Errorf("flag '--%s' requires at least %s unless '--insecure' flag is provided", flag, size) -} - -// MutuallyExclusiveFlags returns an error with mutually exclusive message for -// the given flags. -func MutuallyExclusiveFlags(_ *cli.Context, flag1, flag2 string) error { - return fmt.Errorf("flag '--%s' and flag '--%s' are mutually exclusive", flag1, flag2) -} - -// UnsupportedFlag returns an error with a message saying that the given flag is -// not yet supported. -func UnsupportedFlag(_ *cli.Context, flag string) error { - return fmt.Errorf("flag '--%s' is not yet supported", flag) -} - -// usage returns the command usage text if set or a default usage string. -func usage(ctx *cli.Context) string { - if ctx.Command.UsageText == "" { - return fmt.Sprintf("%s %s [command options]", ctx.App.HelpName, ctx.Command.Name) - } - // keep just the first line and remove markdown - lines := strings.Split(ctx.Command.UsageText, "\n") - return strings.ReplaceAll(lines[0], "**", "") -} - -// FileError is a wrapper for errors of the os package. -func FileError(err error, filename string) error { - if err == nil { - return nil - } - var ( - pathErr *os.PathError - linkErr *os.LinkError - syscallErr *os.SyscallError - ) - switch { - case errors.As(err, &pathErr): - return fmt.Errorf("%s %s failed: %w", pathErr.Op, pathErr.Path, pathErr.Err) - case errors.As(err, &linkErr): - return fmt.Errorf("%s %s %s failed: %w", linkErr.Op, linkErr.Old, linkErr.New, linkErr.Err) - case errors.As(err, &syscallErr): - return fmt.Errorf("%s failed: %w", syscallErr.Syscall, syscallErr.Err) - default: - return Wrap(err, "unexpected error on %s", filename) - } -} - -// FriendlyError is an interface for returning friendly error messages to the user. -type FriendlyError interface { - Message() string -} diff --git a/vendor/github.com/smallstep/cli-utils/fileutil/file.go b/vendor/github.com/smallstep/cli-utils/fileutil/file.go deleted file mode 100644 index 04e00a2..0000000 --- a/vendor/github.com/smallstep/cli-utils/fileutil/file.go +++ /dev/null @@ -1,121 +0,0 @@ -package fileutil - -import ( - "os" - - "github.com/pkg/errors" -) - -// File represents a wrapper on os.File that supports read, write, seek and -// close methods, but they won't be called if an error occurred before. -type File struct { - File *os.File - err error -} - -// OpenFile calls os.OpenFile method and returns the os.File wrapped. -func OpenFile(name string, flag int, perm os.FileMode) (*File, error) { - f, err := os.OpenFile(name, flag, perm) - if err != nil { - return nil, FileError(err, name) - } - return &File{ - File: f, - }, nil -} - -// error writes f.err if it's not set and returns f.err. -func (f *File) error(err error) error { - if f.err == nil && err != nil { - f.err = FileError(err, f.File.Name()) - } - return f.err -} - -// Close wraps `func (*os.File) Close` it will always call Close but the error -// return will be the first error thrown if any. -func (f *File) Close() error { - return f.error(f.File.Close()) -} - -// Read wraps `func (*os.File) Read` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) Read(b []byte) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.Read(b) - return n, f.error(err) -} - -// ReadAt wraps `func (*os.File) ReadAt` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) ReadAt(b []byte, off int64) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.ReadAt(b, off) - return n, f.error(err) -} - -// Seek wraps `func (*os.File) Seek` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) Seek(offset int64, whence int) (ret int64, err error) { - if f.err != nil { - return 0, f.err - } - ret, err = f.File.Seek(offset, whence) - return ret, f.error(err) -} - -// Write wraps `func (*os.File) Write` but doesn't perform the operation if a -// previous error was thrown. -func (f *File) Write(b []byte) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.Write(b) - return n, f.error(err) -} - -// WriteAt wraps `func (*os.File) WriteAt` but doesn't perform the operation if -// a previous error was thrown. -func (f *File) WriteAt(b []byte, off int64) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.WriteAt(b, off) - return n, f.error(err) -} - -// WriteString wraps `func (*os.File) WriteString` but doesn't perform the -// operation if a previous error was thrown. -func (f *File) WriteString(s string) (n int, err error) { - if f.err != nil { - return 0, f.err - } - n, err = f.File.WriteString(s) - return n, f.error(err) -} - -// FileError is a wrapper for errors of the os package. -func FileError(err error, filename string) error { - if err == nil { - return nil - } - var ( - pathErr *os.PathError - linkErr *os.LinkError - syscallErr *os.SyscallError - ) - switch { - case errors.As(err, &pathErr): - return errors.Errorf("%s %s failed: %v", pathErr.Op, pathErr.Path, pathErr.Err) - case errors.As(err, &linkErr): - return errors.Errorf("%s %s %s failed: %v", linkErr.Op, linkErr.Old, linkErr.New, linkErr.Err) - case errors.As(err, &syscallErr): - return errors.Errorf("%s failed: %v", syscallErr.Syscall, syscallErr.Err) - default: - return errors.Wrapf(err, "unexpected error on %s", filename) - } -} diff --git a/vendor/github.com/smallstep/cli-utils/fileutil/write.go b/vendor/github.com/smallstep/cli-utils/fileutil/write.go deleted file mode 100644 index ba8194b..0000000 --- a/vendor/github.com/smallstep/cli-utils/fileutil/write.go +++ /dev/null @@ -1,232 +0,0 @@ -package fileutil - -import ( - "bufio" - "bytes" - "fmt" - "io" - "os" - "strings" - "time" - - "github.com/pkg/errors" - - "github.com/smallstep/cli-utils/command" - "github.com/smallstep/cli-utils/ui" -) - -var ( - // ErrFileExists is the error returned if a file exists. - ErrFileExists = errors.New("file exists") - - // ErrIsDir is the error returned if the file is a directory. - ErrIsDir = errors.New("file is a directory") - - // SnippetHeader is the header of a step generated snippet in a - // configuration file. - SnippetHeader = "# autogenerated by step" - - // SnippetFooter is the header of a step generated snippet in a - // configuration file. - SnippetFooter = "# end" -) - -// WriteFile wraps ioutil.WriteFile with a prompt to overwrite a file if -// the file exists. It returns ErrFileExists if the user picks to not overwrite -// the file. If force is set to true, the prompt will not be presented and the -// file if exists will be overwritten. -func WriteFile(filename string, data []byte, perm os.FileMode) error { - if command.IsForce() { - return os.WriteFile(filename, data, perm) - } - - st, err := os.Stat(filename) - if err != nil { - if os.IsNotExist(err) { - return os.WriteFile(filename, data, perm) - } - return errors.Wrapf(err, "error reading information for %s", filename) - } - - if st.IsDir() { - return ErrIsDir - } - - str, err := ui.Prompt(fmt.Sprintf("Would you like to overwrite %s [y/n]", filename), ui.WithValidateYesNo()) - if err != nil { - return err - } - switch strings.ToLower(strings.TrimSpace(str)) { - case "y", "yes": - case "n", "no": - return ErrFileExists - } - - return os.WriteFile(filename, data, perm) -} - -// AppendNewLine appends the given data at the end of the file. If the last -// character of the file does not contain an LF it prepends it to the data. -func AppendNewLine(filename string, data []byte, perm os.FileMode) error { - f, err := OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, perm) - if err != nil { - return err - } - // Read last character - if st, err := f.File.Stat(); err == nil && st.Size() != 0 { - last := make([]byte, 1) - f.Seek(-1, 2) - f.Read(last) - if last[0] != '\n' { - f.WriteString("\n") - } - } - f.Write(data) - return f.Close() -} - -func writeChunk(filename string, data []byte, hasHeaderFooter bool, header, footer string, perm os.FileMode) error { - // Get file permissions - if st, err := os.Stat(filename); err == nil { - perm = st.Mode() - } else if !os.IsNotExist(err) { - return FileError(err, filename) - } - - // Read file contents - b, err := os.ReadFile(filename) - if err != nil && !os.IsNotExist(err) { - return FileError(err, filename) - } - - // Detect previous configuration - _, start, end := findConfiguration(bytes.NewReader(b), header, footer) - - // Replace previous configuration - f, err := OpenFile(filename, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, perm) - if err != nil { - return FileError(err, filename) - } - if len(b) > 0 { - f.Write(b[:start]) - if start == end { - f.WriteString("\n") - } - } - if !hasHeaderFooter { - fmt.Fprintf(f, "%s @ %s\n", header, time.Now().UTC().Format(time.RFC3339)) - } - f.Write(data) - if !bytes.HasSuffix(data, []byte("\n")) { - f.WriteString("\n") - } - if !hasHeaderFooter { - f.WriteString(footer + "\n") - } - if len(b) > 0 { - f.Write(b[end:]) - } - return f.Close() -} - -// WriteSnippet writes the given data into the given filename. It surrounds the -// data with a default header and footer, and it will replace the previous one. -func WriteSnippet(filename string, data []byte, perm os.FileMode) error { - return writeChunk(filename, data, false, SnippetHeader, SnippetFooter, perm) -} - -// PrependLine prepends the given line into the given filename and removes -// other instances of the line in the file. -func PrependLine(filename string, data []byte, perm os.FileMode) error { - // Get file permissions - if st, err := os.Stat(filename); err == nil { - perm = st.Mode() - } else if !os.IsNotExist(err) { - return FileError(err, filename) - } - - // Read file contents - b, err := os.ReadFile(filename) - if err != nil && !os.IsNotExist(err) { - return FileError(err, filename) - } - - line := string(data) - result := []string{string(data)} - for _, l := range strings.Split(string(b), "\n") { - if l != "" && !strings.HasPrefix(l, line) { - result = append(result, l) - } - } - - if err := os.WriteFile(filename, []byte(strings.Join(result, "\n")), perm); err != nil { - return FileError(err, filename) - } - return nil -} - -// RemoveLine removes a single line which contains the given substring from the -// given file. -func RemoveLine(filename, substr string) error { - var perm os.FileMode - // Get file permissions - st, err := os.Stat(filename) - switch { - case os.IsNotExist(err): - return nil - case err != nil: - return FileError(err, filename) - default: - perm = st.Mode() - } - - // Read file contents - b, err := os.ReadFile(filename) - if err != nil && !os.IsNotExist(err) { - return FileError(err, filename) - } - - old := strings.Split(string(b), "\n") - for i, l := range old { - if !strings.Contains(l, substr) { - continue - } - if err := os.WriteFile(filename, []byte(strings.Join(append(old[:i], old[i+1:]...), "\n")), perm); err != nil { - return FileError(err, filename) - } - break - } - - return nil -} - -type offsetCounter struct { - offset int64 -} - -func (o *offsetCounter) ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { - advance, token, err = bufio.ScanLines(data, atEOF) - o.offset += int64(advance) - return -} - -func findConfiguration(r io.Reader, header, footer string) (lines []string, start, end int64) { - var inConfig bool - counter := new(offsetCounter) - scanner := bufio.NewScanner(r) - scanner.Split(counter.ScanLines) - for scanner.Scan() { - line := scanner.Text() - switch { - case !inConfig && strings.HasPrefix(line, header): - inConfig = true - start = counter.offset - int64(len(line)+1) - case inConfig && strings.HasPrefix(line, footer): - return lines, start, counter.offset - case inConfig: - lines = append(lines, line) - } - } - - return lines, counter.offset, counter.offset -} diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/LICENSE.txt b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/LICENSE.txt deleted file mode 100644 index 2885af3..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/LICENSE.txt +++ /dev/null @@ -1,29 +0,0 @@ -Blackfriday is distributed under the Simplified BSD License: - -> Copyright © 2011 Russ Ross -> All rights reserved. -> -> Redistribution and use in source and binary forms, with or without -> modification, are permitted provided that the following conditions -> are met: -> -> 1. Redistributions of source code must retain the above copyright -> notice, this list of conditions and the following disclaimer. -> -> 2. Redistributions in binary form must reproduce the above -> copyright notice, this list of conditions and the following -> disclaimer in the documentation and/or other materials provided with -> the distribution. -> -> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -> POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/README.md b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/README.md deleted file mode 100644 index 2e0db35..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/README.md +++ /dev/null @@ -1,283 +0,0 @@ -Blackfriday [](https://travis-ci.org/russross/blackfriday) -=========== - -Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It -is paranoid about its input (so you can safely feed it user-supplied -data), it is fast, it supports common extensions (tables, smart -punctuation substitutions, etc.), and it is safe for all utf-8 -(unicode) input. - -HTML output is currently supported, along with Smartypants -extensions. - -It started as a translation from C of [Sundown][3]. - - -Installation ------------- - -Blackfriday is compatible with any modern Go release. With Go 1.7 and git -installed: - - go get gopkg.in/russross/blackfriday.v2 - -will download, compile, and install the package into your `$GOPATH` -directory hierarchy. Alternatively, you can achieve the same if you -import it into a project: - - import "gopkg.in/russross/blackfriday.v2" - -and `go get` without parameters. - - -Versions --------- - -Currently maintained and recommended version of Blackfriday is `v2`. It's being -developed on its own branch: https://github.com/russross/blackfriday/v2. You -should install and import it via [gopkg.in][6] at -`gopkg.in/russross/blackfriday.v2`. - -Version 2 offers a number of improvements over v1: - -* Cleaned up API -* A separate call to [`Parse`][4], which produces an abstract syntax tree for - the document -* Latest bug fixes -* Flexibility to easily add your own rendering extensions - -Potential drawbacks: - -* Our benchmarks show v2 to be slightly slower than v1. Currently in the - ballpark of around 15%. -* API breakage. If you can't afford modifying your code to adhere to the new API - and don't care too much about the new features, v2 is probably not for you. -* Several bug fixes are trailing behind and still need to be forward-ported to - v2. See issue [#348](https://github.com/russross/blackfriday/issues/348) for - tracking. - -Usage ------ - -For the most sensible markdown processing, it is as simple as getting your input -into a byte slice and calling: - -```go -output := blackfriday.Run(input) -``` - -Your input will be parsed and the output rendered with a set of most popular -extensions enabled. If you want the most basic feature set, corresponding with -the bare Markdown specification, use: - -```go -output := blackfriday.Run(input, blackfriday.WithNoExtensions()) -``` - -### Sanitize untrusted content - -Blackfriday itself does nothing to protect against malicious content. If you are -dealing with user-supplied markdown, we recommend running Blackfriday's output -through HTML sanitizer such as [Bluemonday][5]. - -Here's an example of simple usage of Blackfriday together with Bluemonday: - -```go -import ( - "github.com/microcosm-cc/bluemonday" - "github.com/russross/blackfriday" -) - -// ... -unsafe := blackfriday.Run(input) -html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) -``` - -### Custom options - -If you want to customize the set of options, use `blackfriday.WithExtensions`, -`blackfriday.WithRenderer` and `blackfriday.WithRefOverride`. - -You can also check out `blackfriday-tool` for a more complete example -of how to use it. Download and install it using: - - go get github.com/russross/blackfriday-tool - -This is a simple command-line tool that allows you to process a -markdown file using a standalone program. You can also browse the -source directly on github if you are just looking for some example -code: - -* <http://github.com/russross/blackfriday-tool> - -Note that if you have not already done so, installing -`blackfriday-tool` will be sufficient to download and install -blackfriday in addition to the tool itself. The tool binary will be -installed in `$GOPATH/bin`. This is a statically-linked binary that -can be copied to wherever you need it without worrying about -dependencies and library versions. - - -Features --------- - -All features of Sundown are supported, including: - -* **Compatibility**. The Markdown v1.0.3 test suite passes with - the `--tidy` option. Without `--tidy`, the differences are - mostly in whitespace and entity escaping, where blackfriday is - more consistent and cleaner. - -* **Common extensions**, including table support, fenced code - blocks, autolinks, strikethroughs, non-strict emphasis, etc. - -* **Safety**. Blackfriday is paranoid when parsing, making it safe - to feed untrusted user input without fear of bad things - happening. The test suite stress tests this and there are no - known inputs that make it crash. If you find one, please let me - know and send me the input that does it. - - NOTE: "safety" in this context means *runtime safety only*. In order to - protect yourself against JavaScript injection in untrusted content, see - [this example](https://github.com/russross/blackfriday#sanitize-untrusted-content). - -* **Fast processing**. It is fast enough to render on-demand in - most web applications without having to cache the output. - -* **Thread safety**. You can run multiple parsers in different - goroutines without ill effect. There is no dependence on global - shared state. - -* **Minimal dependencies**. Blackfriday only depends on standard - library packages in Go. The source code is pretty - self-contained, so it is easy to add to any project, including - Google App Engine projects. - -* **Standards compliant**. Output successfully validates using the - W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional. - - -Extensions ----------- - -In addition to the standard markdown syntax, this package -implements the following extensions: - -* **Intra-word emphasis supression**. The `_` character is - commonly used inside words when discussing code, so having - markdown interpret it as an emphasis command is usually the - wrong thing. Blackfriday lets you treat all emphasis markers as - normal characters when they occur inside a word. - -* **Tables**. Tables can be created by drawing them in the input - using a simple syntax: - - ``` - Name | Age - --------|------ - Bob | 27 - Alice | 23 - ``` - -* **Fenced code blocks**. In addition to the normal 4-space - indentation to mark code blocks, you can explicitly mark them - and supply a language (to make syntax highlighting simple). Just - mark it like this: - - ```go - func getTrue() bool { - return true - } - ``` - - You can use 3 or more backticks to mark the beginning of the - block, and the same number to mark the end of the block. - -* **Definition lists**. A simple definition list is made of a single-line - term followed by a colon and the definition for that term. - - Cat - : Fluffy animal everyone likes - - Internet - : Vector of transmission for pictures of cats - - Terms must be separated from the previous definition by a blank line. - -* **Footnotes**. A marker in the text that will become a superscript number; - a footnote definition that will be placed in a list of footnotes at the - end of the document. A footnote looks like this: - - This is a footnote.[^1] - - [^1]: the footnote text. - -* **Autolinking**. Blackfriday can find URLs that have not been - explicitly marked as links and turn them into links. - -* **Strikethrough**. Use two tildes (`~~`) to mark text that - should be crossed out. - -* **Hard line breaks**. With this extension enabled newlines in the input - translate into line breaks in the output. This extension is off by default. - -* **Smart quotes**. Smartypants-style punctuation substitution is - supported, turning normal double- and single-quote marks into - curly quotes, etc. - -* **LaTeX-style dash parsing** is an additional option, where `--` - is translated into `–`, and `---` is translated into - `—`. This differs from most smartypants processors, which - turn a single hyphen into an ndash and a double hyphen into an - mdash. - -* **Smart fractions**, where anything that looks like a fraction - is translated into suitable HTML (instead of just a few special - cases like most smartypant processors). For example, `4/5` - becomes `<sup>4</sup>⁄<sub>5</sub>`, which renders as - <sup>4</sup>⁄<sub>5</sub>. - - -Other renderers ---------------- - -Blackfriday is structured to allow alternative rendering engines. Here -are a few of note: - -* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown): - provides a GitHub Flavored Markdown renderer with fenced code block - highlighting, clickable heading anchor links. - - It's not customizable, and its goal is to produce HTML output - equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode), - except the rendering is performed locally. - -* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt, - but for markdown. - -* [LaTeX output](https://bitbucket.org/ambrevar/blackfriday-latex): - renders output as LaTeX. - - -Todo ----- - -* More unit testing -* Improve unicode support. It does not understand all unicode - rules (about what constitutes a letter, a punctuation symbol, - etc.), so it may fail to detect word boundaries correctly in - some instances. It is safe on all utf-8 input. - - -License -------- - -[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt) - - - [1]: https://daringfireball.net/projects/markdown/ "Markdown" - [2]: https://golang.org/ "Go Language" - [3]: https://github.com/vmg/sundown "Sundown" - [4]: https://godoc.org/gopkg.in/russross/blackfriday.v2#Parse "Parse func" - [5]: https://github.com/microcosm-cc/bluemonday "Bluemonday" - [6]: https://labix.org/gopkg.in "gopkg.in" diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/block.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/block.go deleted file mode 100644 index 918d656..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/block.go +++ /dev/null @@ -1,1559 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// Functions to parse block-level elements. -// - -//nolint:gocritic,revive,ineffassign,gosimple,wastedassign // ignore blackfriday -package blackfriday - -import ( - "bytes" - "html" - "regexp" - - "github.com/shurcooL/sanitized_anchor_name" -) - -const ( - charEntity = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});" - escapable = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]" -) - -var ( - reBackslashOrAmp = regexp.MustCompile("[\\&]") - reEntityOrEscapedChar = regexp.MustCompile("(?i)\\\\" + escapable + "|" + charEntity) -) - -// Parse block-level data. -// Note: this function and many that it calls assume that -// the input buffer ends with a newline. -func (p *Markdown) block(data []byte) { - // this is called recursively: enforce a maximum depth - if p.nesting >= p.maxNesting { - return - } - p.nesting++ - - // parse out one block-level construct at a time - for len(data) > 0 { - // prefixed heading: - // - // # Heading 1 - // ## Heading 2 - // ... - // ###### Heading 6 - if p.isPrefixHeading(data) { - data = data[p.prefixHeading(data):] - continue - } - - // block of preformatted HTML: - // - // <div> - // ... - // </div> - if data[0] == '<' { - if i := p.html(data, true); i > 0 { - data = data[i:] - continue - } - } - - // title block - // - // % stuff - // % more stuff - // % even more stuff - if p.extensions&Titleblock != 0 { - if data[0] == '%' { - if i := p.titleBlock(data, true); i > 0 { - data = data[i:] - continue - } - } - } - - // blank lines. note: returns the # of bytes to skip - if i := p.isEmpty(data); i > 0 { - data = data[i:] - continue - } - - // indented code block: - // - // func max(a, b int) int { - // if a > b { - // return a - // } - // return b - // } - if p.codePrefix(data) > 0 { - data = data[p.code(data):] - continue - } - - // fenced code block: - // - // ``` go - // func fact(n int) int { - // if n <= 1 { - // return n - // } - // return n * fact(n-1) - // } - // ``` - if p.extensions&FencedCode != 0 { - if i := p.fencedCodeBlock(data, true); i > 0 { - data = data[i:] - continue - } - } - - // horizontal rule: - // - // ------ - // or - // ****** - // or - // ______ - if p.isHRule(data) { - p.addBlock(HorizontalRule, nil) - var i int - for i = 0; i < len(data) && data[i] != '\n'; i++ { - } - data = data[i:] - continue - } - - // block quote: - // - // > A big quote I found somewhere - // > on the web - if p.quotePrefix(data) > 0 { - data = data[p.quote(data):] - continue - } - - // table: - // - // Name | Age | Phone - // ------|-----|--------- - // Bob | 31 | 555-1234 - // Alice | 27 | 555-4321 - if p.extensions&Tables != 0 { - if i := p.table(data); i > 0 { - data = data[i:] - continue - } - } - - // an itemized/unordered list: - // - // * Item 1 - // * Item 2 - // - // also works with + or - - if p.uliPrefix(data) > 0 { - data = data[p.list(data, 0):] - continue - } - - // a numbered/ordered list: - // - // 1. Item 1 - // 2. Item 2 - if p.oliPrefix(data) > 0 { - data = data[p.list(data, ListTypeOrdered):] - continue - } - - // definition lists: - // - // Term 1 - // : Definition a - // : Definition b - // - // Term 2 - // : Definition c - if p.extensions&DefinitionLists != 0 { - if p.dliPrefix(data) > 0 { - data = data[p.list(data, ListTypeDefinition):] - continue - } - } - - // anything else must look like a normal paragraph - // note: this finds underlined headings, too - data = data[p.paragraph(data):] - } - - p.nesting-- -} - -func (p *Markdown) addBlock(typ NodeType, content []byte) *Node { - p.closeUnmatchedBlocks() - container := p.addChild(typ, 0) - container.content = content - return container -} - -func (p *Markdown) isPrefixHeading(data []byte) bool { - if data[0] != '#' { - return false - } - - if p.extensions&SpaceHeadings != 0 { - level := 0 - for level < 6 && level < len(data) && data[level] == '#' { - level++ - } - if level == len(data) || data[level] != ' ' { - return false - } - } - return true -} - -func (p *Markdown) prefixHeading(data []byte) int { - level := 0 - for level < 6 && level < len(data) && data[level] == '#' { - level++ - } - i := skipChar(data, level, ' ') - end := skipUntilChar(data, i, '\n') - skip := end - id := "" - if p.extensions&HeadingIDs != 0 { - j, k := 0, 0 - // find start/end of heading id - for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ { - } - for k = j + 1; k < end && data[k] != '}'; k++ { - } - // extract heading id iff found - if j < end && k < end { - id = string(data[j+2 : k]) - end = j - skip = k + 1 - for end > 0 && data[end-1] == ' ' { - end-- - } - } - } - for end > 0 && data[end-1] == '#' { - if isBackslashEscaped(data, end-1) { - break - } - end-- - } - for end > 0 && data[end-1] == ' ' { - end-- - } - if end > i { - if id == "" && p.extensions&AutoHeadingIDs != 0 { - id = sanitized_anchor_name.Create(string(data[i:end])) - } - block := p.addBlock(Heading, data[i:end]) - block.HeadingID = id - block.Level = level - } - return skip -} - -func (p *Markdown) isUnderlinedHeading(data []byte) int { - // test of level 1 heading - if data[0] == '=' { - i := skipChar(data, 1, '=') - i = skipChar(data, i, ' ') - if i < len(data) && data[i] == '\n' { - return 1 - } - return 0 - } - - // test of level 2 heading - if data[0] == '-' { - i := skipChar(data, 1, '-') - i = skipChar(data, i, ' ') - if i < len(data) && data[i] == '\n' { - return 2 - } - return 0 - } - - return 0 -} - -func (p *Markdown) titleBlock(data []byte, doRender bool) int { - if data[0] != '%' { - return 0 - } - splitData := bytes.Split(data, []byte("\n")) - var i int - for idx, b := range splitData { - if !bytes.HasPrefix(b, []byte("%")) { - i = idx // - 1 - break - } - } - - data = bytes.Join(splitData[0:i], []byte("\n")) - consumed := len(data) - data = bytes.TrimPrefix(data, []byte("% ")) - data = bytes.Replace(data, []byte("\n% "), []byte("\n"), -1) - block := p.addBlock(Heading, data) - block.Level = 1 - block.IsTitleblock = true - - return consumed -} - -func (p *Markdown) html(data []byte, doRender bool) int { - var i, j int - - // identify the opening tag - if data[0] != '<' { - return 0 - } - curtag, tagfound := p.htmlFindTag(data[1:]) - - // handle special cases - if !tagfound { - // check for an HTML comment - if size := p.htmlComment(data, doRender); size > 0 { - return size - } - - // check for an <hr> tag - if size := p.htmlHr(data, doRender); size > 0 { - return size - } - - // no special case recognized - return 0 - } - - // look for an unindented matching closing tag - // followed by a blank line - found := false - /* - closetag := []byte("\n</" + curtag + ">") - j = len(curtag) + 1 - for !found { - // scan for a closing tag at the beginning of a line - if skip := bytes.Index(data[j:], closetag); skip >= 0 { - j += skip + len(closetag) - } else { - break - } - - // see if it is the only thing on the line - if skip := p.isEmpty(data[j:]); skip > 0 { - // see if it is followed by a blank line/eof - j += skip - if j >= len(data) { - found = true - i = j - } else { - if skip := p.isEmpty(data[j:]); skip > 0 { - j += skip - found = true - i = j - } - } - } - } - */ - - // if not found, try a second pass looking for indented match - // but not if tag is "ins" or "del" (following original Markdown.pl) - if !found && curtag != "ins" && curtag != "del" { - i = 1 - for i < len(data) { - i++ - for i < len(data) && !(data[i-1] == '<' && data[i] == '/') { - i++ - } - - if i+2+len(curtag) >= len(data) { - break - } - - j = p.htmlFindEnd(curtag, data[i-1:]) - - if j > 0 { - i += j - 1 - found = true - break - } - } - } - - if !found { - return 0 - } - - // the end of the block has been found - if doRender { - // trim newlines - end := i - for end > 0 && data[end-1] == '\n' { - end-- - } - finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end])) - } - - return i -} - -func finalizeHTMLBlock(block *Node) { - block.Literal = block.content - block.content = nil -} - -// HTML comment, lax form -func (p *Markdown) htmlComment(data []byte, doRender bool) int { - i := p.inlineHTMLComment(data) - // needs to end with a blank line - if j := p.isEmpty(data[i:]); j > 0 { - size := i + j - if doRender { - // trim trailing newlines - end := size - for end > 0 && data[end-1] == '\n' { - end-- - } - block := p.addBlock(HTMLBlock, data[:end]) - finalizeHTMLBlock(block) - } - return size - } - return 0 -} - -// HR, which is the only self-closing block tag considered -func (p *Markdown) htmlHr(data []byte, doRender bool) int { - if len(data) < 4 { - return 0 - } - if data[0] != '<' || (data[1] != 'h' && data[1] != 'H') || (data[2] != 'r' && data[2] != 'R') { - return 0 - } - if data[3] != ' ' && data[3] != '/' && data[3] != '>' { - // not an <hr> tag after all; at least not a valid one - return 0 - } - i := 3 - for i < len(data) && data[i] != '>' && data[i] != '\n' { - i++ - } - if i < len(data) && data[i] == '>' { - i++ - if j := p.isEmpty(data[i:]); j > 0 { - size := i + j - if doRender { - // trim newlines - end := size - for end > 0 && data[end-1] == '\n' { - end-- - } - finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end])) - } - return size - } - } - return 0 -} - -func (p *Markdown) htmlFindTag(data []byte) (string, bool) { - i := 0 - for i < len(data) && isalnum(data[i]) { - i++ - } - key := string(data[:i]) - if _, ok := blockTags[key]; ok { - return key, true - } - return "", false -} - -func (p *Markdown) htmlFindEnd(tag string, data []byte) int { - // assume data[0] == '<' && data[1] == '/' already tested - if tag == "hr" { - return 2 - } - // check if tag is a match - closetag := []byte("</" + tag + ">") - if !bytes.HasPrefix(data, closetag) { - return 0 - } - i := len(closetag) - - // check that the rest of the line is blank - skip := 0 - if skip = p.isEmpty(data[i:]); skip == 0 { - return 0 - } - i += skip - skip = 0 - - if i >= len(data) { - return i - } - - if p.extensions&LaxHTMLBlocks != 0 { - return i - } - if skip = p.isEmpty(data[i:]); skip == 0 { - // following line must be blank - return 0 - } - - return i + skip -} - -func (*Markdown) isEmpty(data []byte) int { - // it is okay to call isEmpty on an empty buffer - if len(data) == 0 { - return 0 - } - - var i int - for i = 0; i < len(data) && data[i] != '\n'; i++ { - if data[i] != ' ' && data[i] != '\t' { - return 0 - } - } - if i < len(data) && data[i] == '\n' { - i++ - } - return i -} - -func (*Markdown) isHRule(data []byte) bool { - i := 0 - - // skip up to three spaces - for i < 3 && data[i] == ' ' { - i++ - } - - // look at the hrule char - if data[i] != '*' && data[i] != '-' && data[i] != '_' { - return false - } - c := data[i] - - // the whole line must be the char or whitespace - n := 0 - for i < len(data) && data[i] != '\n' { - switch { - case data[i] == c: - n++ - case data[i] != ' ': - return false - } - i++ - } - - return n >= 3 -} - -// isFenceLine checks if there's a fence line (e.g., ``` or ``` go) at the beginning of data, -// and returns the end index if so, or 0 otherwise. It also returns the marker found. -// If syntax is not nil, it gets set to the syntax specified in the fence line. -func isFenceLine(data []byte, syntax *string, oldmarker string) (end int, marker string) { - i, size := 0, 0 - - // skip up to three spaces - for i < len(data) && i < 3 && data[i] == ' ' { - i++ - } - - // check for the marker characters: ~ or ` - if i >= len(data) { - return 0, "" - } - if data[i] != '~' && data[i] != '`' { - return 0, "" - } - - c := data[i] - - // the whole line must be the same char or whitespace - for i < len(data) && data[i] == c { - size++ - i++ - } - - // the marker char must occur at least 3 times - if size < 3 { - return 0, "" - } - marker = string(data[i-size : i]) - - // if this is the end marker, it must match the beginning marker - if oldmarker != "" && marker != oldmarker { - return 0, "" - } - - // TODO(shurcooL): It's probably a good idea to simplify the 2 code paths here - // into one, always get the syntax, and discard it if the caller doesn't care. - if syntax != nil { - syn := 0 - i = skipChar(data, i, ' ') - - if i >= len(data) { - if i == len(data) { - return i, marker - } - return 0, "" - } - - syntaxStart := i - - if data[i] == '{' { - i++ - syntaxStart++ - - for i < len(data) && data[i] != '}' && data[i] != '\n' { - syn++ - i++ - } - - if i >= len(data) || data[i] != '}' { - return 0, "" - } - - // strip all whitespace at the beginning and the end - // of the {} block - for syn > 0 && isspace(data[syntaxStart]) { - syntaxStart++ - syn-- - } - - for syn > 0 && isspace(data[syntaxStart+syn-1]) { - syn-- - } - - i++ - } else { - for i < len(data) && !isspace(data[i]) { - syn++ - i++ - } - } - - *syntax = string(data[syntaxStart : syntaxStart+syn]) - } - - i = skipChar(data, i, ' ') - if i >= len(data) || data[i] != '\n' { - if i == len(data) { - return i, marker - } - return 0, "" - } - return i + 1, marker // Take newline into account. -} - -// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning, -// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects. -// If doRender is true, a final newline is mandatory to recognize the fenced code block. -func (p *Markdown) fencedCodeBlock(data []byte, doRender bool) int { - var syntax string - beg, marker := isFenceLine(data, &syntax, "") - if beg == 0 || beg >= len(data) { - return 0 - } - - var work bytes.Buffer - work.Write([]byte(syntax)) - work.WriteByte('\n') - - for { - // safe to assume beg < len(data) - - // check for the end of the code block - fenceEnd, _ := isFenceLine(data[beg:], nil, marker) - if fenceEnd != 0 { - beg += fenceEnd - break - } - - // copy the current line - end := skipUntilChar(data, beg, '\n') + 1 - - // did we reach the end of the buffer without a closing marker? - if end >= len(data) { - return 0 - } - - // verbatim copy to the working buffer - if doRender { - work.Write(data[beg:end]) - } - beg = end - } - - if doRender { - block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer - block.IsFenced = true - finalizeCodeBlock(block) - } - - return beg -} - -func unescapeChar(str []byte) []byte { - if str[0] == '\\' { - return []byte{str[1]} - } - return []byte(html.UnescapeString(string(str))) -} - -func unescapeString(str []byte) []byte { - if reBackslashOrAmp.Match(str) { - return reEntityOrEscapedChar.ReplaceAllFunc(str, unescapeChar) - } - return str -} - -func finalizeCodeBlock(block *Node) { - if block.IsFenced { - newlinePos := bytes.IndexByte(block.content, '\n') - firstLine := block.content[:newlinePos] - rest := block.content[newlinePos+1:] - block.Info = unescapeString(bytes.Trim(firstLine, "\n")) - block.Literal = rest - } else { - block.Literal = block.content - } - block.content = nil -} - -func (p *Markdown) table(data []byte) int { - table := p.addBlock(Table, nil) - i, columns := p.tableHeader(data) - if i == 0 { - p.tip = table.Parent - table.Unlink() - return 0 - } - - p.addBlock(TableBody, nil) - - for i < len(data) { - pipes, rowStart := 0, i - for ; i < len(data) && data[i] != '\n'; i++ { - if data[i] == '|' { - pipes++ - } - } - - if pipes == 0 { - i = rowStart - break - } - - // include the newline in data sent to tableRow - if i < len(data) && data[i] == '\n' { - i++ - } - p.tableRow(data[rowStart:i], columns, false) - } - - return i -} - -// check if the specified position is preceded by an odd number of backslashes -func isBackslashEscaped(data []byte, i int) bool { - backslashes := 0 - for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' { - backslashes++ - } - return backslashes&1 == 1 -} - -func (p *Markdown) tableHeader(data []byte) (size int, columns []CellAlignFlags) { - i := 0 - colCount := 1 - for i = 0; i < len(data) && data[i] != '\n'; i++ { - if data[i] == '|' && !isBackslashEscaped(data, i) { - colCount++ - } - } - - // doesn't look like a table header - if colCount == 1 { - return - } - - // include the newline in the data sent to tableRow - j := i - if j < len(data) && data[j] == '\n' { - j++ - } - header := data[:j] - - // column count ignores pipes at beginning or end of line - if data[0] == '|' { - colCount-- - } - if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) { - colCount-- - } - - columns = make([]CellAlignFlags, colCount) - - // move on to the header underline - i++ - if i >= len(data) { - return - } - - if data[i] == '|' && !isBackslashEscaped(data, i) { - i++ - } - i = skipChar(data, i, ' ') - - // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3 - // and trailing | optional on last column - col := 0 - for i < len(data) && data[i] != '\n' { - dashes := 0 - - if data[i] == ':' { - i++ - columns[col] |= TableAlignmentLeft - dashes++ - } - for i < len(data) && data[i] == '-' { - i++ - dashes++ - } - if i < len(data) && data[i] == ':' { - i++ - columns[col] |= TableAlignmentRight - dashes++ - } - for i < len(data) && data[i] == ' ' { - i++ - } - if i == len(data) { - return - } - // end of column test is messy - switch { - case dashes < 3: - // not a valid column - return - - case data[i] == '|' && !isBackslashEscaped(data, i): - // marker found, now skip past trailing whitespace - col++ - i++ - for i < len(data) && data[i] == ' ' { - i++ - } - - // trailing junk found after last column - if col >= colCount && i < len(data) && data[i] != '\n' { - return - } - - case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount: - // something else found where marker was required - return - - case data[i] == '\n': - // marker is optional for the last column - col++ - - default: - // trailing junk found after last column - return - } - } - if col != colCount { - return - } - - p.addBlock(TableHead, nil) - p.tableRow(header, columns, true) - size = i - if size < len(data) && data[size] == '\n' { - size++ - } - return -} - -func (p *Markdown) tableRow(data []byte, columns []CellAlignFlags, header bool) { - p.addBlock(TableRow, nil) - i, col := 0, 0 - - if data[i] == '|' && !isBackslashEscaped(data, i) { - i++ - } - - for col = 0; col < len(columns) && i < len(data); col++ { - for i < len(data) && data[i] == ' ' { - i++ - } - - cellStart := i - - for i < len(data) && (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' { - i++ - } - - cellEnd := i - - // skip the end-of-cell marker, possibly taking us past end of buffer - i++ - - for cellEnd > cellStart && cellEnd-1 < len(data) && data[cellEnd-1] == ' ' { - cellEnd-- - } - - cell := p.addBlock(TableCell, data[cellStart:cellEnd]) - cell.IsHeader = header - cell.Align = columns[col] - } - - // pad it out with empty columns to get the right number - for ; col < len(columns); col++ { - cell := p.addBlock(TableCell, nil) - cell.IsHeader = header - cell.Align = columns[col] - } - - // silently ignore rows with too many cells -} - -// returns blockquote prefix length -func (p *Markdown) quotePrefix(data []byte) int { - i := 0 - for i < 3 && i < len(data) && data[i] == ' ' { - i++ - } - if i < len(data) && data[i] == '>' { - if i+1 < len(data) && data[i+1] == ' ' { - return i + 2 - } - return i + 1 - } - return 0 -} - -// blockquote ends with at least one blank line -// followed by something without a blockquote prefix -func (p *Markdown) terminateBlockquote(data []byte, beg, end int) bool { - if p.isEmpty(data[beg:]) <= 0 { - return false - } - if end >= len(data) { - return true - } - return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 -} - -// parse a blockquote fragment -func (p *Markdown) quote(data []byte) int { - block := p.addBlock(BlockQuote, nil) - var raw bytes.Buffer - beg, end := 0, 0 - for beg < len(data) { - end = beg - // Step over whole lines, collecting them. While doing that, check for - // fenced code and if one's found, incorporate it altogether, - // irregardless of any contents inside it - for end < len(data) && data[end] != '\n' { - if p.extensions&FencedCode != 0 { - if i := p.fencedCodeBlock(data[end:], false); i > 0 { - // -1 to compensate for the extra end++ after the loop: - end += i - 1 - break - } - } - end++ - } - if end < len(data) && data[end] == '\n' { - end++ - } - if pre := p.quotePrefix(data[beg:]); pre > 0 { - // skip the prefix - beg += pre - } else if p.terminateBlockquote(data, beg, end) { - break - } - // this line is part of the blockquote - raw.Write(data[beg:end]) - beg = end - } - p.block(raw.Bytes()) - p.finalize(block) - return end -} - -// returns prefix length for block code -func (p *Markdown) codePrefix(data []byte) int { - if len(data) >= 1 && data[0] == '\t' { - return 1 - } - if len(data) >= 4 && data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ' { - return 4 - } - return 0 -} - -func (p *Markdown) code(data []byte) int { - var work bytes.Buffer - - i := 0 - for i < len(data) { - beg := i - for i < len(data) && data[i] != '\n' { - i++ - } - if i < len(data) && data[i] == '\n' { - i++ - } - - blankline := p.isEmpty(data[beg:i]) > 0 - if pre := p.codePrefix(data[beg:i]); pre > 0 { - beg += pre - } else if !blankline { - // non-empty, non-prefixed line breaks the pre - i = beg - break - } - - // verbatim copy to the working buffer - if blankline { - work.WriteByte('\n') - } else { - work.Write(data[beg:i]) - } - } - - // trim all the \n off the end of work - workbytes := work.Bytes() - eol := len(workbytes) - for eol > 0 && workbytes[eol-1] == '\n' { - eol-- - } - if eol != len(workbytes) { - work.Truncate(eol) - } - - work.WriteByte('\n') - - block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer - block.IsFenced = false - finalizeCodeBlock(block) - - return i -} - -// returns unordered list item prefix -func (p *Markdown) uliPrefix(data []byte) int { - i := 0 - // start with up to 3 spaces - for i < len(data) && i < 3 && data[i] == ' ' { - i++ - } - if i >= len(data)-1 { - return 0 - } - // need one of {'*', '+', '-'} followed by a space or a tab - if (data[i] != '*' && data[i] != '+' && data[i] != '-') || - (data[i+1] != ' ' && data[i+1] != '\t') { - return 0 - } - return i + 2 -} - -// returns ordered list item prefix -func (p *Markdown) oliPrefix(data []byte) int { - i := 0 - - // start with up to 3 spaces - for i < 3 && i < len(data) && data[i] == ' ' { - i++ - } - - // count the digits - start := i - for i < len(data) && data[i] >= '0' && data[i] <= '9' { - i++ - } - if start == i || i >= len(data)-1 { - return 0 - } - - // we need >= 1 digits followed by a dot and a space or a tab - if data[i] != '.' || !(data[i+1] == ' ' || data[i+1] == '\t') { - return 0 - } - return i + 2 -} - -// returns definition list item prefix -func (p *Markdown) dliPrefix(data []byte) int { - if len(data) < 2 { - return 0 - } - i := 0 - // need a ':' followed by a space or a tab - if data[i] != ':' || !(data[i+1] == ' ' || data[i+1] == '\t') { - return 0 - } - for i < len(data) && data[i] == ' ' { - i++ - } - return i + 2 -} - -// parse ordered or unordered list block -func (p *Markdown) list(data []byte, flags ListType) int { - i := 0 - flags |= ListItemBeginningOfList - block := p.addBlock(List, nil) - block.ListFlags = flags - block.Tight = true - - for i < len(data) { - skip := p.listItem(data[i:], &flags) - if flags&ListItemContainsBlock != 0 { - block.ListData.Tight = false - } - i += skip - if skip == 0 || flags&ListItemEndOfList != 0 { - break - } - flags &= ^ListItemBeginningOfList - } - - above := block.Parent - finalizeList(block) - p.tip = above - return i -} - -// Returns true if block ends with a blank line, descending if needed -// into lists and sublists. -func endsWithBlankLine(block *Node) bool { - // TODO: figure this out. Always false now. - for block != nil { - //if block.lastLineBlank { - //return true - //} - t := block.Type - if t == List || t == Item { - block = block.LastChild - } else { - break - } - } - return false -} - -func finalizeList(block *Node) { - block.open = false - item := block.FirstChild - for item != nil { - // check for non-final list item ending with blank line: - if endsWithBlankLine(item) && item.Next != nil { - block.ListData.Tight = false - break - } - // recurse into children of list item, to see if there are spaces - // between any of them: - subItem := item.FirstChild - for subItem != nil { - if endsWithBlankLine(subItem) && (item.Next != nil || subItem.Next != nil) { - block.ListData.Tight = false - break - } - subItem = subItem.Next - } - item = item.Next - } -} - -// Parse a single list item. -// Assumes initial prefix is already removed if this is a sublist. -func (p *Markdown) listItem(data []byte, flags *ListType) int { - // keep track of the indentation of the first line - itemIndent := 0 - if data[0] == '\t' { - itemIndent += 4 - } else { - for itemIndent < 3 && data[itemIndent] == ' ' { - itemIndent++ - } - } - - var bulletChar byte = '*' - i := p.uliPrefix(data) - if i == 0 { - i = p.oliPrefix(data) - } else { - bulletChar = data[i-2] - } - if i == 0 { - i = p.dliPrefix(data) - // reset definition term flag - if i > 0 { - *flags &= ^ListTypeTerm - } - } - if i == 0 { - // if in definition list, set term flag and continue - if *flags&ListTypeDefinition != 0 { - *flags |= ListTypeTerm - } else { - return 0 - } - } - - // skip leading whitespace on first line - for i < len(data) && data[i] == ' ' { - i++ - } - - // find the end of the line - line := i - for i > 0 && i < len(data) && data[i-1] != '\n' { - i++ - } - - // get working buffer - var raw bytes.Buffer - - // put the first line into the working buffer - raw.Write(data[line:i]) - line = i - - // process the following lines - containsBlankLine := false - sublist := 0 - lastChunkSize := 0 - -gatherlines: - for line < len(data) { - i++ - - // find the end of this line - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // if it is an empty line, guess that it is part of this item - // and move on to the next line - if p.isEmpty(data[line:i]) > 0 { - containsBlankLine = true - line = i - continue - } - - // calculate the indentation - indent := 0 - indentIndex := 0 - if data[line] == '\t' { - indentIndex++ - indent += 4 - } else { - for indent < 4 && line+indent < i && data[line+indent] == ' ' { - indent++ - indentIndex++ - } - } - - chunk := data[line+indentIndex : i] - - // evaluate how this line fits in - switch { - // is this a nested list item? - case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) || - p.oliPrefix(chunk) > 0 || - p.dliPrefix(chunk) > 0: - - if containsBlankLine { - *flags |= ListItemContainsBlock - } - - // to be a nested list, it must be indented more - // if not, it is the next item in the same list - if indent <= itemIndent { - break gatherlines - } - - // is this the first item in the nested list? - if sublist == 0 { - if p.dliPrefix(chunk) > 0 { - sublist = raw.Len() - lastChunkSize - } else { - sublist = raw.Len() - } - } - - // is this a nested prefix heading? - case p.isPrefixHeading(chunk): - // if the heading is not indented, it is not nested in the list - // and thus ends the list - if containsBlankLine && indent < 4 { - *flags |= ListItemEndOfList - break gatherlines - } - *flags |= ListItemContainsBlock - - // anything following an empty line is only part - // of this item if it is indented 4 spaces - // (regardless of the indentation of the beginning of the item) - case containsBlankLine && indent < 4: - if *flags&ListTypeDefinition != 0 && i < len(data)-1 { - // is the next item still a part of this list? - next := i - for next < len(data) && data[next] != '\n' { - next++ - } - for next < len(data)-1 && data[next] == '\n' { - next++ - } - if i < len(data)-1 && data[i] != ':' && data[next] != ':' { - *flags |= ListItemEndOfList - } - } else { - *flags |= ListItemEndOfList - } - break gatherlines - - // a blank line means this should be parsed as a block - case containsBlankLine: - raw.WriteByte('\n') - *flags |= ListItemContainsBlock - } - - // if this line was preceded by one or more blanks, - // re-introduce the blank into the buffer - if containsBlankLine { - containsBlankLine = false - raw.WriteByte('\n') - } - - // add the line into the working buffer without prefix - raw.Write(data[line+indentIndex : i]) - - // remember how much was written into raw, if this turns out to be a - // definition list we'll need this number to know where the sublist starts - lastChunkSize = i - (line + indentIndex) - - line = i - } - - rawBytes := raw.Bytes() - - block := p.addBlock(Item, nil) - block.ListFlags = *flags - block.Tight = false - block.BulletChar = bulletChar - block.Delimiter = '.' // Only '.' is possible in Markdown, but ')' will also be possible in CommonMark - - // render the contents of the list item - if *flags&ListItemContainsBlock != 0 && *flags&ListTypeTerm == 0 { - // intermediate render of block item, except for definition term - if sublist > 0 { - p.block(rawBytes[:sublist]) - p.block(rawBytes[sublist:]) - } else { - p.block(rawBytes) - } - } else { - // intermediate render of inline item - if sublist > 0 { - child := p.addChild(Paragraph, 0) - child.content = rawBytes[:sublist] - p.block(rawBytes[sublist:]) - } else { - child := p.addChild(Paragraph, 0) - child.content = rawBytes - } - } - return line -} - -// render a single paragraph that has already been parsed out -func (p *Markdown) renderParagraph(data []byte) { - if len(data) == 0 { - return - } - - // trim leading spaces - beg := 0 - for data[beg] == ' ' { - beg++ - } - - end := len(data) - // trim trailing newline - if data[len(data)-1] == '\n' { - end-- - } - - // trim trailing spaces - for end > beg && data[end-1] == ' ' { - end-- - } - - p.addBlock(Paragraph, data[beg:end]) -} - -func (p *Markdown) paragraph(data []byte) int { - // prev: index of 1st char of previous line - // line: index of 1st char of current line - // i: index of cursor/end of current line - var prev, line, i int - tabSize := TabSizeDefault - if p.extensions&TabSizeEight != 0 { - tabSize = TabSizeDouble - } - // keep going until we find something to mark the end of the paragraph - for i < len(data) { - // mark the beginning of the current line - prev = line - current := data[i:] - line = i - - // did we find a reference or a footnote? If so, end a paragraph - // preceding it and report that we have consumed up to the end of that - // reference: - if refEnd := isReference(p, current, tabSize); refEnd > 0 { - p.renderParagraph(data[:i]) - return i + refEnd - } - - // did we find a blank line marking the end of the paragraph? - if n := p.isEmpty(current); n > 0 { - // did this blank line followed by a definition list item? - if p.extensions&DefinitionLists != 0 { - if i < len(data)-1 && data[i+1] == ':' { - return p.list(data[prev:], ListTypeDefinition) - } - } - - p.renderParagraph(data[:i]) - return i + n - } - - // an underline under some text marks a heading, so our paragraph ended on prev line - if i > 0 { - if level := p.isUnderlinedHeading(current); level > 0 { - // render the paragraph - p.renderParagraph(data[:prev]) - - // ignore leading and trailing whitespace - eol := i - 1 - for prev < eol && data[prev] == ' ' { - prev++ - } - for eol > prev && data[eol-1] == ' ' { - eol-- - } - - id := "" - if p.extensions&AutoHeadingIDs != 0 { - id = sanitized_anchor_name.Create(string(data[prev:eol])) - } - - block := p.addBlock(Heading, data[prev:eol]) - block.Level = level - block.HeadingID = id - - // find the end of the underline - for i < len(data) && data[i] != '\n' { - i++ - } - return i - } - } - - // if the next line starts a block of HTML, then the paragraph ends here - if p.extensions&LaxHTMLBlocks != 0 { - if data[i] == '<' && p.html(current, false) > 0 { - // rewind to before the HTML block - p.renderParagraph(data[:i]) - return i - } - } - - // if there's a prefixed heading or a horizontal rule after this, paragraph is over - if p.isPrefixHeading(current) || p.isHRule(current) { - p.renderParagraph(data[:i]) - return i - } - - // if there's a fenced code block, paragraph is over - if p.extensions&FencedCode != 0 { - if p.fencedCodeBlock(current, false) > 0 { - p.renderParagraph(data[:i]) - return i - } - } - - // if there's a definition list item, prev line is a definition term - if p.extensions&DefinitionLists != 0 { - if p.dliPrefix(current) != 0 { - ret := p.list(data[prev:], ListTypeDefinition) - return ret - } - } - - // if there's a list after this, paragraph is over - if p.extensions&NoEmptyLineBeforeBlock != 0 { - if p.uliPrefix(current) != 0 || - p.oliPrefix(current) != 0 || - p.quotePrefix(current) != 0 || - p.codePrefix(current) != 0 { - p.renderParagraph(data[:i]) - return i - } - } - - // otherwise, scan to the beginning of the next line - nl := bytes.IndexByte(data[i:], '\n') - if nl >= 0 { - i += nl + 1 - } else { - i += len(data[i:]) - } - } - - p.renderParagraph(data[:i]) - return i -} - -func skipChar(data []byte, start int, char byte) int { - i := start - for i < len(data) && data[i] == char { - i++ - } - return i -} - -func skipUntilChar(text []byte, start int, char byte) int { - i := start - for i < len(text) && text[i] != char { - i++ - } - return i -} diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/doc.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/doc.go deleted file mode 100644 index 5b3fa98..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Package blackfriday is a markdown processor. -// -// It translates plain text with simple formatting rules into an AST, which can -// then be further processed to HTML (provided by Blackfriday itself) or other -// formats (provided by the community). -// -// The simplest way to invoke Blackfriday is to call the Run function. It will -// take a text input and produce a text output in HTML (or other format). -// -// A slightly more sophisticated way to use Blackfriday is to create a Markdown -// processor and to call Parse, which returns a syntax tree for the input -// document. You can leverage Blackfriday's parsing for content extraction from -// markdown documents. You can assign a custom renderer and set various options -// to the Markdown processor. -// -// If you're interested in calling Blackfriday from command line, see -// https://github.com/russross/blackfriday-tool. -package blackfriday diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/esc.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/esc.go deleted file mode 100644 index 6385f27..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/esc.go +++ /dev/null @@ -1,34 +0,0 @@ -package blackfriday - -import ( - "html" - "io" -) - -var htmlEscaper = [256][]byte{ - '&': []byte("&"), - '<': []byte("<"), - '>': []byte(">"), - '"': []byte("""), -} - -func escapeHTML(w io.Writer, s []byte) { - var start, end int - for end < len(s) { - escSeq := htmlEscaper[s[end]] - if escSeq != nil { - w.Write(s[start:end]) - w.Write(escSeq) - start = end + 1 - } - end++ - } - if start < len(s) && end <= len(s) { - w.Write(s[start:end]) - } -} - -func escLink(w io.Writer, text []byte) { - unesc := html.UnescapeString(string(text)) - escapeHTML(w, []byte(unesc)) -} diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/html.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/html.go deleted file mode 100644 index 9fbf820..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/html.go +++ /dev/null @@ -1,941 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// -// HTML rendering backend -// -// - -//nolint:gocritic,unused,revive // ignore blackfriday -package blackfriday - -import ( - "bytes" - "fmt" - "io" - "regexp" - "strings" -) - -// HTMLFlags control optional behavior of HTML renderer. -type HTMLFlags int - -// HTML renderer configuration options. -const ( - HTMLFlagsNone HTMLFlags = 0 - SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks - SkipImages // Skip embedded images - SkipLinks // Skip all links - Safelink // Only link to trusted protocols - NofollowLinks // Only link with rel="nofollow" - NoreferrerLinks // Only link with rel="noreferrer" - HrefTargetBlank // Add a blank target - CompletePage // Generate a complete HTML page - UseXHTML // Generate XHTML output instead of HTML - FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source - Smartypants // Enable smart punctuation substitutions - SmartypantsFractions // Enable smart fractions (with Smartypants) - SmartypantsDashes // Enable smart dashes (with Smartypants) - SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants) - SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering - SmartypantsQuotesNBSP // Enable « French guillemets » (with Smartypants) - TOC // Generate a table of contents -) - -var ( - htmlTagRe = regexp.MustCompile("(?i)^" + htmlTag) -) - -const ( - htmlTag = "(?:" + openTag + "|" + closeTag + "|" + htmlComment + "|" + - processingInstruction + "|" + declaration + "|" + cdata + ")" - closeTag = "</" + tagName + "\\s*[>]" - openTag = "<" + tagName + attribute + "*" + "\\s*/?>" - attribute = "(?:" + "\\s+" + attributeName + attributeValueSpec + "?)" - attributeValue = "(?:" + unquotedValue + "|" + singleQuotedValue + "|" + doubleQuotedValue + ")" - attributeValueSpec = "(?:" + "\\s*=" + "\\s*" + attributeValue + ")" - attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*" - cdata = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>" - declaration = "<![A-Z]+" + "\\s+[^>]*>" - doubleQuotedValue = "\"[^\"]*\"" - htmlComment = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->" - processingInstruction = "[<][?].*?[?][>]" - singleQuotedValue = "'[^']*'" - tagName = "[A-Za-z][A-Za-z0-9-]*" - unquotedValue = "[^\"'=<>`\\x00-\\x20]+" -) - -// HTMLRendererParameters is a collection of supplementary parameters tweaking -// the behavior of various parts of HTML renderer. -type HTMLRendererParameters struct { - // Prepend this text to each relative URL. - AbsolutePrefix string - // Add this text to each footnote anchor, to ensure uniqueness. - FootnoteAnchorPrefix string - // Show this text inside the <a> tag for a footnote return link, if the - // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string - // <sup>[return]</sup> is used. - FootnoteReturnLinkContents string - // If set, add this text to the front of each Heading ID, to ensure - // uniqueness. - HeadingIDPrefix string - // If set, add this text to the back of each Heading ID, to ensure uniqueness. - HeadingIDSuffix string - - Title string // Document title (used if CompletePage is set) - CSS string // Optional CSS file URL (used if CompletePage is set) - Icon string // Optional icon file URL (used if CompletePage is set) - - Flags HTMLFlags // Flags allow customizing this renderer's behavior -} - -// HTMLRenderer is a type that implements the Renderer interface for HTML output. -// -// Do not create this directly, instead use the NewHTMLRenderer function. -type HTMLRenderer struct { - HTMLRendererParameters - - closeTag string // how to end singleton tags: either " />" or ">" - - // Track heading IDs to prevent ID collision in a single generation. - headingIDs map[string]int - - lastOutputLen int - disableTags int - - sr *SPRenderer -} - -const ( - xhtmlClose = " />" - htmlClose = ">" -) - -// NewHTMLRenderer creates and configures an HTMLRenderer object, which -// satisfies the Renderer interface. -func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer { - // configure the rendering engine - closeTag := htmlClose - if params.Flags&UseXHTML != 0 { - closeTag = xhtmlClose - } - - if params.FootnoteReturnLinkContents == "" { - params.FootnoteReturnLinkContents = `<sup>[return]</sup>` - } - - return &HTMLRenderer{ - HTMLRendererParameters: params, - - closeTag: closeTag, - headingIDs: make(map[string]int), - - sr: NewSmartypantsRenderer(params.Flags), - } -} - -func isHTMLTag(tag []byte, tagname string) bool { - found, _ := findHTMLTagPos(tag, tagname) - return found -} - -// Look for a character, but ignore it when it's in any kind of quotes, it -// might be JavaScript -func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int { - inSingleQuote := false - inDoubleQuote := false - inGraveQuote := false - i := start - for i < len(html) { - switch { - case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote: - return i - case html[i] == '\'': - inSingleQuote = !inSingleQuote - case html[i] == '"': - inDoubleQuote = !inDoubleQuote - case html[i] == '`': - inGraveQuote = !inGraveQuote - } - i++ - } - return start -} - -func findHTMLTagPos(tag []byte, tagname string) (bool, int) { - i := 0 - if i < len(tag) && tag[0] != '<' { - return false, -1 - } - i++ - i = skipSpace(tag, i) - - if i < len(tag) && tag[i] == '/' { - i++ - } - - i = skipSpace(tag, i) - j := 0 - for ; i < len(tag); i, j = i+1, j+1 { - if j >= len(tagname) { - break - } - - if strings.ToLower(string(tag[i]))[0] != tagname[j] { - return false, -1 - } - } - - if i == len(tag) { - return false, -1 - } - - rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>') - if rightAngle >= i { - return true, rightAngle - } - - return false, -1 -} - -func skipSpace(tag []byte, i int) int { - for i < len(tag) && isspace(tag[i]) { - i++ - } - return i -} - -func isRelativeLink(link []byte) (yes bool) { - // a tag begin with '#' - if link[0] == '#' { - return true - } - - // link begin with '/' but not '//', the second maybe a protocol relative link - if len(link) >= 2 && link[0] == '/' && link[1] != '/' { - return true - } - - // only the root '/' - if len(link) == 1 && link[0] == '/' { - return true - } - - // current directory : begin with "./" - if bytes.HasPrefix(link, []byte("./")) { - return true - } - - // parent directory : begin with "../" - if bytes.HasPrefix(link, []byte("../")) { - return true - } - - return false -} - -func (r *HTMLRenderer) ensureUniqueHeadingID(id string) string { - for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { - tmp := fmt.Sprintf("%s-%d", id, count+1) - - if _, tmpFound := r.headingIDs[tmp]; !tmpFound { - r.headingIDs[id] = count + 1 - id = tmp - } else { - id = id + "-1" - } - } - - if _, found := r.headingIDs[id]; !found { - r.headingIDs[id] = 0 - } - - return id -} - -func (r *HTMLRenderer) addAbsPrefix(link []byte) []byte { - if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { - newDest := r.AbsolutePrefix - if link[0] != '/' { - newDest += "/" - } - newDest += string(link) - return []byte(newDest) - } - return link -} - -func appendLinkAttrs(attrs []string, flags HTMLFlags, link []byte) []string { - if isRelativeLink(link) { - return attrs - } - val := []string{} - if flags&NofollowLinks != 0 { - val = append(val, "nofollow") - } - if flags&NoreferrerLinks != 0 { - val = append(val, "noreferrer") - } - if flags&HrefTargetBlank != 0 { - attrs = append(attrs, "target=\"_blank\"") - } - if len(val) == 0 { - return attrs - } - attr := fmt.Sprintf("rel=%q", strings.Join(val, " ")) - return append(attrs, attr) -} - -func isMailto(link []byte) bool { - return bytes.HasPrefix(link, []byte("mailto:")) -} - -func needSkipLink(flags HTMLFlags, dest []byte) bool { - if flags&SkipLinks != 0 { - return true - } - return flags&Safelink != 0 && !isSafeLink(dest) && !isMailto(dest) -} - -func isSmartypantable(node *Node) bool { - pt := node.Parent.Type - return pt != Link && pt != CodeBlock && pt != Code -} - -func appendLanguageAttr(attrs []string, info []byte) []string { - if len(info) == 0 { - return attrs - } - endOfLang := bytes.IndexAny(info, "\t ") - if endOfLang < 0 { - endOfLang = len(info) - } - return append(attrs, fmt.Sprintf("class=\"language-%s\"", info[:endOfLang])) -} - -func (r *HTMLRenderer) tag(w io.Writer, name []byte, attrs []string) { - w.Write(name) - if len(attrs) > 0 { - w.Write(spaceBytes) - w.Write([]byte(strings.Join(attrs, " "))) - } - w.Write(gtBytes) - r.lastOutputLen = 1 -} - -func footnoteRef(prefix string, node *Node) []byte { - urlFrag := prefix + string(slugify(node.Destination)) - anchor := fmt.Sprintf(`<a rel="footnote" href="#fn:%s">%d</a>`, urlFrag, node.NoteID) - return []byte(fmt.Sprintf(`<sup class="footnote-ref" id="fnref:%s">%s</sup>`, urlFrag, anchor)) -} - -func footnoteItem(prefix string, slug []byte) []byte { - return []byte(fmt.Sprintf(`<li id="fn:%s%s">`, prefix, slug)) -} - -func footnoteReturnLink(prefix, returnLink string, slug []byte) []byte { - const format = ` <a class="footnote-return" href="#fnref:%s%s">%s</a>` - return []byte(fmt.Sprintf(format, prefix, slug, returnLink)) -} - -func itemOpenCR(node *Node) bool { - if node.Prev == nil { - return false - } - ld := node.Parent.ListData - return !ld.Tight && ld.ListFlags&ListTypeDefinition == 0 -} - -func skipParagraphTags(node *Node) bool { - grandparent := node.Parent.Parent - if grandparent == nil || grandparent.Type != List { - return false - } - tightOrTerm := grandparent.Tight || node.Parent.ListFlags&ListTypeTerm != 0 - return grandparent.Type == List && tightOrTerm -} - -func cellAlignment(align CellAlignFlags) string { - switch align { - case TableAlignmentLeft: - return "left" - case TableAlignmentRight: - return "right" - case TableAlignmentCenter: - return "center" - default: - return "" - } -} - -func (r *HTMLRenderer) out(w io.Writer, text []byte) { - if r.disableTags > 0 { - w.Write(htmlTagRe.ReplaceAll(text, []byte{})) - } else { - w.Write(text) - } - r.lastOutputLen = len(text) -} - -func (r *HTMLRenderer) cr(w io.Writer) { - if r.lastOutputLen > 0 { - r.out(w, nlBytes) - } -} - -var ( - nlBytes = []byte{'\n'} - gtBytes = []byte{'>'} - spaceBytes = []byte{' '} -) - -var ( - brTag = []byte("<br>") - brXHTMLTag = []byte("<br />") - emTag = []byte("<em>") - emCloseTag = []byte("</em>") - strongTag = []byte("<strong>") - strongCloseTag = []byte("</strong>") - delTag = []byte("<del>") - delCloseTag = []byte("</del>") - ttTag = []byte("<tt>") - ttCloseTag = []byte("</tt>") - aTag = []byte("<a") - aCloseTag = []byte("</a>") - preTag = []byte("<pre>") - preCloseTag = []byte("</pre>") - codeTag = []byte("<code>") - codeCloseTag = []byte("</code>") - pTag = []byte("<p>") - pCloseTag = []byte("</p>") - blockquoteTag = []byte("<blockquote>") - blockquoteCloseTag = []byte("</blockquote>") - hrTag = []byte("<hr>") - hrXHTMLTag = []byte("<hr />") - ulTag = []byte("<ul>") - ulCloseTag = []byte("</ul>") - olTag = []byte("<ol>") - olCloseTag = []byte("</ol>") - dlTag = []byte("<dl>") - dlCloseTag = []byte("</dl>") - liTag = []byte("<li>") - liCloseTag = []byte("</li>") - ddTag = []byte("<dd>") - ddCloseTag = []byte("</dd>") - dtTag = []byte("<dt>") - dtCloseTag = []byte("</dt>") - tableTag = []byte("<table>") - tableCloseTag = []byte("</table>") - tdTag = []byte("<td") - tdCloseTag = []byte("</td>") - thTag = []byte("<th") - thCloseTag = []byte("</th>") - theadTag = []byte("<thead>") - theadCloseTag = []byte("</thead>") - tbodyTag = []byte("<tbody>") - tbodyCloseTag = []byte("</tbody>") - trTag = []byte("<tr>") - trCloseTag = []byte("</tr>") - h1Tag = []byte("<h1") - h1CloseTag = []byte("</h1>") - h2Tag = []byte("<h2") - h2CloseTag = []byte("</h2>") - h3Tag = []byte("<h3") - h3CloseTag = []byte("</h3>") - h4Tag = []byte("<h4") - h4CloseTag = []byte("</h4>") - h5Tag = []byte("<h5") - h5CloseTag = []byte("</h5>") - h6Tag = []byte("<h6") - h6CloseTag = []byte("</h6>") - - footnotesDivBytes = []byte("\n<div class=\"footnotes\">\n\n") - footnotesCloseDivBytes = []byte("\n</div>\n") -) - -func headingTagsFromLevel(level int) ([]byte, []byte) { - switch level { - case 1: - return h1Tag, h1CloseTag - case 2: - return h2Tag, h2CloseTag - case 3: - return h3Tag, h3CloseTag - case 4: - return h4Tag, h4CloseTag - case 5: - return h5Tag, h5CloseTag - default: - return h6Tag, h6CloseTag - } -} - -func (r *HTMLRenderer) outHRTag(w io.Writer) { - if r.Flags&UseXHTML == 0 { - r.out(w, hrTag) - } else { - r.out(w, hrXHTMLTag) - } -} - -// RenderNode is a default renderer of a single node of a syntax tree. For -// block nodes it will be called twice: first time with entering=true, second -// time with entering=false, so that it could know when it's working on an open -// tag and when on close. It writes the result to w. -// -// The return value is a way to tell the calling walker to adjust its walk -// pattern: e.g. it can terminate the traversal by returning Terminate. Or it -// can ask the walker to skip a subtree of this node by returning SkipChildren. -// The typical behavior is to return GoToNext, which asks for the usual -// traversal to the next node. -func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus { - attrs := []string{} - switch node.Type { - case Text: - if r.Flags&Smartypants != 0 { - var tmp bytes.Buffer - escapeHTML(&tmp, node.Literal) - r.sr.Process(w, tmp.Bytes()) - } else { - if node.Parent.Type == Link { - escLink(w, node.Literal) - } else { - escapeHTML(w, node.Literal) - } - } - case Softbreak: - r.cr(w) - // TODO: make it configurable via out(renderer.softbreak) - case Hardbreak: - if r.Flags&UseXHTML == 0 { - r.out(w, brTag) - } else { - r.out(w, brXHTMLTag) - } - r.cr(w) - case Emph: - if entering { - r.out(w, emTag) - } else { - r.out(w, emCloseTag) - } - case Strong: - if entering { - r.out(w, strongTag) - } else { - r.out(w, strongCloseTag) - } - case Del: - if entering { - r.out(w, delTag) - } else { - r.out(w, delCloseTag) - } - case HTMLSpan: - if r.Flags&SkipHTML != 0 { - break - } - r.out(w, node.Literal) - case Link: - // mark it but don't link it if it is not a safe link: no smartypants - dest := node.LinkData.Destination - if needSkipLink(r.Flags, dest) { - if entering { - r.out(w, ttTag) - } else { - r.out(w, ttCloseTag) - } - } else { - if entering { - dest = r.addAbsPrefix(dest) - var hrefBuf bytes.Buffer - hrefBuf.WriteString("href=\"") - escLink(&hrefBuf, dest) - hrefBuf.WriteByte('"') - attrs = append(attrs, hrefBuf.String()) - if node.NoteID != 0 { - r.out(w, footnoteRef(r.FootnoteAnchorPrefix, node)) - break - } - attrs = appendLinkAttrs(attrs, r.Flags, dest) - if len(node.LinkData.Title) > 0 { - var titleBuff bytes.Buffer - titleBuff.WriteString("title=\"") - escapeHTML(&titleBuff, node.LinkData.Title) - titleBuff.WriteByte('"') - attrs = append(attrs, titleBuff.String()) - } - r.tag(w, aTag, attrs) - } else { - if node.NoteID != 0 { - break - } - r.out(w, aCloseTag) - } - } - case Image: - if r.Flags&SkipImages != 0 { - return SkipChildren - } - if entering { - dest := node.LinkData.Destination - dest = r.addAbsPrefix(dest) - if r.disableTags == 0 { - //if options.safe && potentiallyUnsafe(dest) { - //out(w, `<img src="" alt="`) - //} else { - r.out(w, []byte(`<img src="`)) - escLink(w, dest) - r.out(w, []byte(`" alt="`)) - //} - } - r.disableTags++ - } else { - r.disableTags-- - if r.disableTags == 0 { - if node.LinkData.Title != nil { - r.out(w, []byte(`" title="`)) - escapeHTML(w, node.LinkData.Title) - } - r.out(w, []byte(`" />`)) - } - } - case Code: - r.out(w, codeTag) - escapeHTML(w, node.Literal) - r.out(w, codeCloseTag) - case Document: - break - case Paragraph: - if skipParagraphTags(node) { - break - } - if entering { - // TODO: untangle this clusterfuck about when the newlines need - // to be added and when not. - if node.Prev != nil { - switch node.Prev.Type { - case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule: - r.cr(w) - } - } - if node.Parent.Type == BlockQuote && node.Prev == nil { - r.cr(w) - } - r.out(w, pTag) - } else { - r.out(w, pCloseTag) - if !(node.Parent.Type == Item && node.Next == nil) { - r.cr(w) - } - } - case BlockQuote: - if entering { - r.cr(w) - r.out(w, blockquoteTag) - } else { - r.out(w, blockquoteCloseTag) - r.cr(w) - } - case HTMLBlock: - if r.Flags&SkipHTML != 0 { - break - } - r.cr(w) - r.out(w, node.Literal) - r.cr(w) - case Heading: - openTag, closeTag := headingTagsFromLevel(node.Level) - if entering { - if node.IsTitleblock { - attrs = append(attrs, `class="title"`) - } - if node.HeadingID != "" { - id := r.ensureUniqueHeadingID(node.HeadingID) - if r.HeadingIDPrefix != "" { - id = r.HeadingIDPrefix + id - } - if r.HeadingIDSuffix != "" { - id = id + r.HeadingIDSuffix - } - attrs = append(attrs, fmt.Sprintf(`id="%s"`, id)) - } - r.cr(w) - r.tag(w, openTag, attrs) - } else { - r.out(w, closeTag) - if !(node.Parent.Type == Item && node.Next == nil) { - r.cr(w) - } - } - case HorizontalRule: - r.cr(w) - r.outHRTag(w) - r.cr(w) - case List: - openTag := ulTag - closeTag := ulCloseTag - if node.ListFlags&ListTypeOrdered != 0 { - openTag = olTag - closeTag = olCloseTag - } - if node.ListFlags&ListTypeDefinition != 0 { - openTag = dlTag - closeTag = dlCloseTag - } - if entering { - if node.IsFootnotesList { - r.out(w, footnotesDivBytes) - r.outHRTag(w) - r.cr(w) - } - r.cr(w) - if node.Parent.Type == Item && node.Parent.Parent.Tight { - r.cr(w) - } - r.tag(w, openTag[:len(openTag)-1], attrs) - r.cr(w) - } else { - r.out(w, closeTag) - //cr(w) - //if node.parent.Type != Item { - // cr(w) - //} - if node.Parent.Type == Item && node.Next != nil { - r.cr(w) - } - if node.Parent.Type == Document || node.Parent.Type == BlockQuote { - r.cr(w) - } - if node.IsFootnotesList { - r.out(w, footnotesCloseDivBytes) - } - } - case Item: - openTag := liTag - closeTag := liCloseTag - if node.ListFlags&ListTypeDefinition != 0 { - openTag = ddTag - closeTag = ddCloseTag - } - if node.ListFlags&ListTypeTerm != 0 { - openTag = dtTag - closeTag = dtCloseTag - } - if entering { - if itemOpenCR(node) { - r.cr(w) - } - if node.ListData.RefLink != nil { - slug := slugify(node.ListData.RefLink) - r.out(w, footnoteItem(r.FootnoteAnchorPrefix, slug)) - break - } - r.out(w, openTag) - } else { - if node.ListData.RefLink != nil { - slug := slugify(node.ListData.RefLink) - if r.Flags&FootnoteReturnLinks != 0 { - r.out(w, footnoteReturnLink(r.FootnoteAnchorPrefix, r.FootnoteReturnLinkContents, slug)) - } - } - r.out(w, closeTag) - r.cr(w) - } - case CodeBlock: - attrs = appendLanguageAttr(attrs, node.Info) - r.cr(w) - r.out(w, preTag) - r.tag(w, codeTag[:len(codeTag)-1], attrs) - escapeHTML(w, node.Literal) - r.out(w, codeCloseTag) - r.out(w, preCloseTag) - if node.Parent.Type != Item { - r.cr(w) - } - case Table: - if entering { - r.cr(w) - r.out(w, tableTag) - } else { - r.out(w, tableCloseTag) - r.cr(w) - } - case TableCell: - openTag := tdTag - closeTag := tdCloseTag - if node.IsHeader { - openTag = thTag - closeTag = thCloseTag - } - if entering { - align := cellAlignment(node.Align) - if align != "" { - attrs = append(attrs, fmt.Sprintf(`align="%s"`, align)) - } - if node.Prev == nil { - r.cr(w) - } - r.tag(w, openTag, attrs) - } else { - r.out(w, closeTag) - r.cr(w) - } - case TableHead: - if entering { - r.cr(w) - r.out(w, theadTag) - } else { - r.out(w, theadCloseTag) - r.cr(w) - } - case TableBody: - if entering { - r.cr(w) - r.out(w, tbodyTag) - // XXX: this is to adhere to a rather silly test. Should fix test. - if node.FirstChild == nil { - r.cr(w) - } - } else { - r.out(w, tbodyCloseTag) - r.cr(w) - } - case TableRow: - if entering { - r.cr(w) - r.out(w, trTag) - } else { - r.out(w, trCloseTag) - r.cr(w) - } - default: - panic("Unknown node type " + node.Type.String()) - } - return GoToNext -} - -// RenderHeader writes HTML document preamble and TOC if requested. -func (r *HTMLRenderer) RenderHeader(w io.Writer, ast *Node) { - r.writeDocumentHeader(w) - if r.Flags&TOC != 0 { - r.writeTOC(w, ast) - } -} - -// RenderFooter writes HTML document footer. -func (r *HTMLRenderer) RenderFooter(w io.Writer, ast *Node) { - if r.Flags&CompletePage == 0 { - return - } - io.WriteString(w, "\n</body>\n</html>\n") -} - -func (r *HTMLRenderer) writeDocumentHeader(w io.Writer) { - if r.Flags&CompletePage == 0 { - return - } - ending := "" - if r.Flags&UseXHTML != 0 { - io.WriteString(w, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ") - io.WriteString(w, "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n") - io.WriteString(w, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n") - ending = " /" - } else { - io.WriteString(w, "<!DOCTYPE html>\n") - io.WriteString(w, "<html>\n") - } - io.WriteString(w, "<head>\n") - io.WriteString(w, " <title>") - if r.Flags&Smartypants != 0 { - r.sr.Process(w, []byte(r.Title)) - } else { - escapeHTML(w, []byte(r.Title)) - } - io.WriteString(w, "</title>\n") - io.WriteString(w, " <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v") - io.WriteString(w, Version) - io.WriteString(w, "\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - io.WriteString(w, " <meta charset=\"utf-8\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - if r.CSS != "" { - io.WriteString(w, " <link rel=\"stylesheet\" type=\"text/css\" href=\"") - escapeHTML(w, []byte(r.CSS)) - io.WriteString(w, "\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - } - if r.Icon != "" { - io.WriteString(w, " <link rel=\"icon\" type=\"image/x-icon\" href=\"") - escapeHTML(w, []byte(r.Icon)) - io.WriteString(w, "\"") - io.WriteString(w, ending) - io.WriteString(w, ">\n") - } - io.WriteString(w, "</head>\n") - io.WriteString(w, "<body>\n\n") -} - -func (r *HTMLRenderer) writeTOC(w io.Writer, ast *Node) { - buf := bytes.Buffer{} - - inHeading := false - tocLevel := 0 - headingCount := 0 - - ast.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Heading && !node.HeadingData.IsTitleblock { - inHeading = entering - if entering { - node.HeadingID = fmt.Sprintf("toc_%d", headingCount) - if node.Level == tocLevel { - buf.WriteString("</li>\n\n<li>") - } else if node.Level < tocLevel { - for node.Level < tocLevel { - tocLevel-- - buf.WriteString("</li>\n</ul>") - } - buf.WriteString("</li>\n\n<li>") - } else { - for node.Level > tocLevel { - tocLevel++ - buf.WriteString("\n<ul>\n<li>") - } - } - - fmt.Fprintf(&buf, `<a href="#toc_%d">`, headingCount) - headingCount++ - } else { - buf.WriteString("</a>") - } - return GoToNext - } - - if inHeading { - return r.RenderNode(&buf, node, entering) - } - - return GoToNext - }) - - for ; tocLevel > 0; tocLevel-- { - buf.WriteString("</li>\n</ul>") - } - - if buf.Len() > 0 { - io.WriteString(w, "<nav>\n") - w.Write(buf.Bytes()) - io.WriteString(w, "\n\n</nav>\n") - } - r.lastOutputLen = buf.Len() -} diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/inline.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/inline.go deleted file mode 100644 index 70557d5..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/inline.go +++ /dev/null @@ -1,1217 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// Functions to parse inline elements. -// - -//nolint:gocritic,whitespace,wastedassign,revive // ignore blackfriday -package blackfriday - -import ( - "bytes" - "regexp" - "strconv" -) - -var ( - urlRe = `((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+` - anchorRe = regexp.MustCompile(`^(<a\shref="` + urlRe + `"(\stitle="[^"<>]+")?\s?>` + urlRe + `<\/a>)`) - - // TODO: improve this regexp to catch all possible entities: - htmlEntityRe = regexp.MustCompile(`&[a-z]{2,5};`) -) - -// Functions to parse text within a block -// Each function returns the number of chars taken care of -// data is the complete block being rendered -// offset is the number of valid chars before the current cursor - -func (p *Markdown) inline(currBlock *Node, data []byte) { - // handlers might call us recursively: enforce a maximum depth - if p.nesting >= p.maxNesting || len(data) == 0 { - return - } - p.nesting++ - beg, end := 0, 0 - for end < len(data) { - handler := p.inlineCallback[data[end]] - if handler != nil { - if consumed, node := handler(p, data, end); consumed == 0 { - // No action from the callback. - end++ - } else { - // Copy inactive chars into the output. - currBlock.AppendChild(text(data[beg:end])) - if node != nil { - currBlock.AppendChild(node) - } - // Skip past whatever the callback used. - beg = end + consumed - end = beg - } - } else { - end++ - } - } - if beg < len(data) { - if data[end-1] == '\n' { - end-- - } - currBlock.AppendChild(text(data[beg:end])) - } - p.nesting-- -} - -// single and double emphasis parsing -func emphasis(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - c := data[0] - - if len(data) > 2 && data[1] != c { - // whitespace cannot follow an opening emphasis; - // strikethrough only takes two characters '~~' - if c == '~' || isspace(data[1]) { - return 0, nil - } - ret, node := helperEmphasis(p, data[1:], c) - if ret == 0 { - return 0, nil - } - - return ret + 1, node - } - - if len(data) > 3 && data[1] == c && data[2] != c { - if isspace(data[2]) { - return 0, nil - } - ret, node := helperDoubleEmphasis(p, data[2:], c) - if ret == 0 { - return 0, nil - } - - return ret + 2, node - } - - if len(data) > 4 && data[1] == c && data[2] == c && data[3] != c { - if c == '~' || isspace(data[3]) { - return 0, nil - } - ret, node := helperTripleEmphasis(p, data, 3, c) - if ret == 0 { - return 0, nil - } - - return ret + 3, node - } - - return 0, nil -} - -func codeSpan(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - nb := 0 - - // count the number of backticks in the delimiter - for nb < len(data) && data[nb] == '`' { - nb++ - } - - // find the next delimiter - i, end := 0, 0 - for end = nb; end < len(data) && i < nb; end++ { - if data[end] == '`' { - i++ - } else { - i = 0 - } - } - - // no matching delimiter? - if i < nb && end >= len(data) { - return 0, nil - } - - // trim outside whitespace - fBegin := nb - for fBegin < end && data[fBegin] == ' ' { - fBegin++ - } - - fEnd := end - nb - for fEnd > fBegin && data[fEnd-1] == ' ' { - fEnd-- - } - - // render the code span - if fBegin != fEnd { - code := NewNode(Code) - code.Literal = data[fBegin:fEnd] - return end, code - } - - return end, nil -} - -// newline preceded by two spaces becomes <br> -func maybeLineBreak(p *Markdown, data []byte, offset int) (int, *Node) { - origOffset := offset - for offset < len(data) && data[offset] == ' ' { - offset++ - } - - if offset < len(data) && data[offset] == '\n' { - if offset-origOffset >= 2 { - return offset - origOffset + 1, NewNode(Hardbreak) - } - return offset - origOffset, nil - } - return 0, nil -} - -// newline without two spaces works when HardLineBreak is enabled -func lineBreak(p *Markdown, data []byte, offset int) (int, *Node) { - if p.extensions&HardLineBreak != 0 { - return 1, NewNode(Hardbreak) - } - return 0, nil -} - -type linkType int - -const ( - linkNormal linkType = iota - linkImg - linkDeferredFootnote - linkInlineFootnote -) - -func isReferenceStyleLink(data []byte, pos int, t linkType) bool { - if t == linkDeferredFootnote { - return false - } - return pos < len(data)-1 && data[pos] == '[' && data[pos+1] != '^' -} - -func maybeImage(p *Markdown, data []byte, offset int) (int, *Node) { - if offset < len(data)-1 && data[offset+1] == '[' { - return link(p, data, offset) - } - return 0, nil -} - -func maybeInlineFootnote(p *Markdown, data []byte, offset int) (int, *Node) { - if offset < len(data)-1 && data[offset+1] == '[' { - return link(p, data, offset) - } - return 0, nil -} - -// '[': parse a link or an image or a footnote -func link(p *Markdown, data []byte, offset int) (int, *Node) { - // no links allowed inside regular links, footnote, and deferred footnotes - if p.insideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') { - return 0, nil - } - - var t linkType - switch { - // special case: ![^text] == deferred footnote (that follows something with - // an exclamation point) - case p.extensions&Footnotes != 0 && len(data)-1 > offset && data[offset+1] == '^': - t = linkDeferredFootnote - // ![alt] == image - case offset >= 0 && data[offset] == '!': - t = linkImg - offset++ - // ^[text] == inline footnote - // [^refId] == deferred footnote - case p.extensions&Footnotes != 0: - if offset >= 0 && data[offset] == '^' { - t = linkInlineFootnote - offset++ - } else if len(data)-1 > offset && data[offset+1] == '^' { - t = linkDeferredFootnote - } - // [text] == regular link - default: - t = linkNormal - } - - data = data[offset:] - - var ( - i = 1 - noteID int - title, link, altContent []byte - textHasNl = false - ) - - if t == linkDeferredFootnote { - i++ - } - - // look for the matching closing bracket - for level := 1; level > 0 && i < len(data); i++ { - switch { - case data[i] == '\n': - textHasNl = true - - case data[i-1] == '\\': - continue - - case data[i] == '[': - level++ - - case data[i] == ']': - level-- - if level <= 0 { - i-- // compensate for extra i++ in for loop - } - } - } - - if i >= len(data) { - return 0, nil - } - - txtE := i - i++ - var footnoteNode *Node - - // skip any amount of whitespace or newline - // (this is much more lax than original markdown syntax) - for i < len(data) && isspace(data[i]) { - i++ - } - - // inline style link - switch { - case i < len(data) && data[i] == '(': - // skip initial whitespace - i++ - - for i < len(data) && isspace(data[i]) { - i++ - } - - linkB := i - - // look for link end: ' " ) - findlinkend: - for i < len(data) { - switch { - case data[i] == '\\': - i += 2 - - case data[i] == ')' || data[i] == '\'' || data[i] == '"': - break findlinkend - - default: - i++ - } - } - - if i >= len(data) { - return 0, nil - } - linkE := i - - // look for title end if present - titleB, titleE := 0, 0 - if data[i] == '\'' || data[i] == '"' { - i++ - titleB = i - - findtitleend: - for i < len(data) { - switch { - case data[i] == '\\': - i += 2 - - case data[i] == ')': - break findtitleend - - default: - i++ - } - } - - if i >= len(data) { - return 0, nil - } - - // skip whitespace after title - titleE = i - 1 - for titleE > titleB && isspace(data[titleE]) { - titleE-- - } - - // check for closing quote presence - if data[titleE] != '\'' && data[titleE] != '"' { - titleB, titleE = 0, 0 - linkE = i - } - } - - // remove whitespace at the end of the link - for linkE > linkB && isspace(data[linkE-1]) { - linkE-- - } - - // remove optional angle brackets around the link - if data[linkB] == '<' { - linkB++ - } - if data[linkE-1] == '>' { - linkE-- - } - - // build escaped link and title - if linkE > linkB { - link = data[linkB:linkE] - } - - if titleE > titleB { - title = data[titleB:titleE] - } - - i++ - - // reference style link - case isReferenceStyleLink(data, i, t): - var id []byte - altContentConsidered := false - - // look for the id - i++ - linkB := i - for i < len(data) && data[i] != ']' { - i++ - } - if i >= len(data) { - return 0, nil - } - linkE := i - - // find the reference - if linkB == linkE { - if textHasNl { - var b bytes.Buffer - - for j := 1; j < txtE; j++ { - switch { - case data[j] != '\n': - b.WriteByte(data[j]) - case data[j-1] != ' ': - b.WriteByte(' ') - } - } - - id = b.Bytes() - } else { - id = data[1:txtE] - altContentConsidered = true - } - } else { - id = data[linkB:linkE] - } - - // find the reference with matching id - lr, ok := p.getRef(string(id)) - if !ok { - return 0, nil - } - - // keep link and title from reference - link = lr.link - title = lr.title - if altContentConsidered { - altContent = lr.text - } - i++ - - // shortcut reference style link or reference or inline footnote - default: - var id []byte - - // craft the id - if textHasNl { - var b bytes.Buffer - - for j := 1; j < txtE; j++ { - switch { - case data[j] != '\n': - b.WriteByte(data[j]) - case data[j-1] != ' ': - b.WriteByte(' ') - } - } - - id = b.Bytes() - } else { - if t == linkDeferredFootnote { - id = data[2:txtE] // get rid of the ^ - } else { - id = data[1:txtE] - } - } - - footnoteNode = NewNode(Item) - if t == linkInlineFootnote { - // create a new reference - noteID = len(p.notes) + 1 - - var fragment []byte - if len(id) > 0 { - if len(id) < 16 { - fragment = make([]byte, len(id)) - } else { - fragment = make([]byte, 16) - } - copy(fragment, slugify(id)) - } else { - fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteID))...) - } - - ref := &reference{ - noteID: noteID, - hasBlock: false, - link: fragment, - title: id, - footnote: footnoteNode, - } - - p.notes = append(p.notes, ref) - - link = ref.link - title = ref.title - } else { - // find the reference with matching id - lr, ok := p.getRef(string(id)) - if !ok { - return 0, nil - } - - if t == linkDeferredFootnote { - lr.noteID = len(p.notes) + 1 - lr.footnote = footnoteNode - p.notes = append(p.notes, lr) - } - - // keep link and title from reference - link = lr.link - // if inline footnote, title == footnote contents - title = lr.title - noteID = lr.noteID - } - - // rewind the whitespace - i = txtE + 1 - } - - var uLink []byte - if t == linkNormal || t == linkImg { - if len(link) > 0 { - var uLinkBuf bytes.Buffer - unescapeText(&uLinkBuf, link) - uLink = uLinkBuf.Bytes() - } - - // links need something to click on and somewhere to go - if len(uLink) == 0 || (t == linkNormal && txtE <= 1) { - return 0, nil - } - } - - // call the relevant rendering function - var linkNode *Node - switch t { - case linkNormal: - linkNode = NewNode(Link) - linkNode.Destination = normalizeURI(uLink) - linkNode.Title = title - if len(altContent) > 0 { - linkNode.AppendChild(text(altContent)) - } else { - // links cannot contain other links, so turn off link parsing - // temporarily and recurse - insideLink := p.insideLink - p.insideLink = true - p.inline(linkNode, data[1:txtE]) - p.insideLink = insideLink - } - - case linkImg: - linkNode = NewNode(Image) - linkNode.Destination = uLink - linkNode.Title = title - linkNode.AppendChild(text(data[1:txtE])) - i++ - - case linkInlineFootnote, linkDeferredFootnote: - linkNode = NewNode(Link) - linkNode.Destination = link - linkNode.Title = title - linkNode.NoteID = noteID - linkNode.Footnote = footnoteNode - if t == linkInlineFootnote { - i++ - } - - default: - return 0, nil - } - - return i, linkNode -} - -func (p *Markdown) inlineHTMLComment(data []byte) int { - if len(data) < 5 { - return 0 - } - if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' { - return 0 - } - i := 5 - // scan for an end-of-comment marker, across lines if necessary - for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') { - i++ - } - // no end-of-comment marker - if i >= len(data) { - return 0 - } - return i + 1 -} - -func stripMailto(link []byte) []byte { - if bytes.HasPrefix(link, []byte("mailto://")) { - return link[9:] - } else if bytes.HasPrefix(link, []byte("mailto:")) { - return link[7:] - } else { - return link - } -} - -// autolinkType specifies a kind of autolink that gets detected. -type autolinkType int - -// These are the possible flag values for the autolink renderer. -const ( - notAutolink autolinkType = iota - normalAutolink - emailAutolink -) - -// '<' when tags or autolinks are allowed -func leftAngle(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - altype, end := tagLength(data) - if size := p.inlineHTMLComment(data); size > 0 { - end = size - } - if end > 2 { - if altype != notAutolink { - var uLink bytes.Buffer - unescapeText(&uLink, data[1:end+1-2]) - if uLink.Len() > 0 { - link := uLink.Bytes() - node := NewNode(Link) - node.Destination = link - if altype == emailAutolink { - node.Destination = append([]byte("mailto:"), link...) - } - node.AppendChild(text(stripMailto(link))) - return end, node - } - } else { - htmlTag := NewNode(HTMLSpan) - htmlTag.Literal = data[:end] - return end, htmlTag - } - } - - return end, nil -} - -// '\\' backslash escape -var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~") - -func escape(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - if len(data) > 1 { - if p.extensions&BackslashLineBreak != 0 && data[1] == '\n' { - return 2, NewNode(Hardbreak) - } - if bytes.IndexByte(escapeChars, data[1]) < 0 { - return 0, nil - } - - return 2, text(data[1:2]) - } - - return 2, nil -} - -func unescapeText(ob *bytes.Buffer, src []byte) { - i := 0 - for i < len(src) { - org := i - for i < len(src) && src[i] != '\\' { - i++ - } - - if i > org { - ob.Write(src[org:i]) - } - - if i+1 >= len(src) { - break - } - - ob.WriteByte(src[i+1]) - i += 2 - } -} - -// '&' escaped when it doesn't belong to an entity -// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; -func entity(p *Markdown, data []byte, offset int) (int, *Node) { - data = data[offset:] - - end := 1 - - if end < len(data) && data[end] == '#' { - end++ - } - - for end < len(data) && isalnum(data[end]) { - end++ - } - - if end < len(data) && data[end] == ';' { - end++ // real entity - } else { - return 0, nil // lone '&' - } - - ent := data[:end] - // undo & escaping or it will be converted to &amp; by another - // escaper in the renderer - if bytes.Equal(ent, []byte("&")) { - ent = []byte{'&'} - } - - return end, text(ent) -} - -func linkEndsWithEntity(data []byte, linkEnd int) bool { - entityRanges := htmlEntityRe.FindAllIndex(data[:linkEnd], -1) - return entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd -} - -// hasPrefixCaseInsensitive is a custom implementation of -// -// strings.HasPrefix(strings.ToLower(s), prefix) -// -// we rolled our own because ToLower pulls in a huge machinery of lowercasing -// anything from Unicode and that's very slow. Since this func will only be -// used on ASCII protocol prefixes, we can take shortcuts. -func hasPrefixCaseInsensitive(s, prefix []byte) bool { - if len(s) < len(prefix) { - return false - } - delta := byte('a' - 'A') - for i, b := range prefix { - if b != s[i] && b != s[i]+delta { - return false - } - } - return true -} - -var protocolPrefixes = [][]byte{ - []byte("http://"), - []byte("https://"), - []byte("ftp://"), - []byte("file://"), - []byte("mailto:"), -} - -const shortestPrefix = 6 // len("ftp://"), the shortest of the above - -func maybeAutoLink(p *Markdown, data []byte, offset int) (int, *Node) { - // quick check to rule out most false hits - if p.insideLink || len(data) < offset+shortestPrefix { - return 0, nil - } - for _, prefix := range protocolPrefixes { - endOfHead := offset + 8 // 8 is the len() of the longest prefix - if endOfHead > len(data) { - endOfHead = len(data) - } - if hasPrefixCaseInsensitive(data[offset:endOfHead], prefix) { - return autoLink(p, data, offset) - } - } - return 0, nil -} - -func autoLink(p *Markdown, data []byte, offset int) (int, *Node) { - // Now a more expensive check to see if we're not inside an anchor element - anchorStart := offset - offsetFromAnchor := 0 - for anchorStart > 0 && data[anchorStart] != '<' { - anchorStart-- - offsetFromAnchor++ - } - - anchorStr := anchorRe.Find(data[anchorStart:]) - if anchorStr != nil { - anchorClose := NewNode(HTMLSpan) - anchorClose.Literal = anchorStr[offsetFromAnchor:] - return len(anchorStr) - offsetFromAnchor, anchorClose - } - - // scan backward for a word boundary - rewind := 0 - for offset-rewind > 0 && rewind <= 7 && isletter(data[offset-rewind-1]) { - rewind++ - } - if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters - return 0, nil - } - - origData := data - data = data[offset-rewind:] - - if !isSafeLink(data) { - return 0, nil - } - - linkEnd := 0 - for linkEnd < len(data) && !isEndOfLink(data[linkEnd]) { - linkEnd++ - } - - // Skip punctuation at the end of the link - if (data[linkEnd-1] == '.' || data[linkEnd-1] == ',') && data[linkEnd-2] != '\\' { - linkEnd-- - } - - // But don't skip semicolon if it's a part of escaped entity: - if data[linkEnd-1] == ';' && data[linkEnd-2] != '\\' && !linkEndsWithEntity(data, linkEnd) { - linkEnd-- - } - - // See if the link finishes with a punctuation sign that can be closed. - var copen byte - switch data[linkEnd-1] { - case '"': - copen = '"' - case '\'': - copen = '\'' - case ')': - copen = '(' - case ']': - copen = '[' - case '}': - copen = '{' - default: - copen = 0 - } - - if copen != 0 { - bufEnd := offset - rewind + linkEnd - 2 - - openDelim := 1 - - /* Try to close the final punctuation sign in this same line; - * if we managed to close it outside of the URL, that means that it's - * not part of the URL. If it closes inside the URL, that means it - * is part of the URL. - * - * Examples: - * - * foo http://www.pokemon.com/Pikachu_(Electric) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo (http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric) - * - * foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => http://www.pokemon.com/Pikachu_(Electric)) - * - * (foo http://www.pokemon.com/Pikachu_(Electric)) bar - * => foo http://www.pokemon.com/Pikachu_(Electric) - */ - - for bufEnd >= 0 && origData[bufEnd] != '\n' && openDelim != 0 { - if origData[bufEnd] == data[linkEnd-1] { - openDelim++ - } - - if origData[bufEnd] == copen { - openDelim-- - } - - bufEnd-- - } - - if openDelim == 0 { - linkEnd-- - } - } - - var uLink bytes.Buffer - unescapeText(&uLink, data[:linkEnd]) - - if uLink.Len() > 0 { - node := NewNode(Link) - node.Destination = uLink.Bytes() - node.AppendChild(text(uLink.Bytes())) - return linkEnd, node - } - - return linkEnd, nil -} - -func isEndOfLink(char byte) bool { - return isspace(char) || char == '<' -} - -var validUris = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")} -var validPaths = [][]byte{[]byte("/"), []byte("./"), []byte("../")} - -func isSafeLink(link []byte) bool { - for _, path := range validPaths { - if len(link) >= len(path) && bytes.Equal(link[:len(path)], path) { - if len(link) == len(path) { - return true - } else if isalnum(link[len(path)]) { - return true - } - } - } - - for _, prefix := range validUris { - // TODO: handle unicode here - // case-insensitive prefix test - if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) { - return true - } - } - - return false -} - -// return the length of the given tag, or 0 is it's not valid -func tagLength(data []byte) (autolink autolinkType, end int) { - var i, j int - - // a valid tag can't be shorter than 3 chars - if len(data) < 3 { - return notAutolink, 0 - } - - // begins with a '<' optionally followed by '/', followed by letter or number - if data[0] != '<' { - return notAutolink, 0 - } - if data[1] == '/' { - i = 2 - } else { - i = 1 - } - - if !isalnum(data[i]) { - return notAutolink, 0 - } - - // scheme test - autolink = notAutolink - - // try to find the beginning of an URI - for i < len(data) && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') { - i++ - } - - if i > 1 && i < len(data) && data[i] == '@' { - if j = isMailtoAutoLink(data[i:]); j != 0 { - return emailAutolink, i + j - } - } - - if i > 2 && i < len(data) && data[i] == ':' { - autolink = normalAutolink - i++ - } - - // complete autolink test: no whitespace or ' or " - switch { - case i >= len(data): - autolink = notAutolink - case autolink != notAutolink: - j = i - - for i < len(data) { - if data[i] == '\\' { - i += 2 - } else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || isspace(data[i]) { - break - } else { - i++ - } - - } - - if i >= len(data) { - return autolink, 0 - } - if i > j && data[i] == '>' { - return autolink, i + 1 - } - - // one of the forbidden chars has been found - autolink = notAutolink - } - i += bytes.IndexByte(data[i:], '>') - if i < 0 { - return autolink, 0 - } - return autolink, i + 1 -} - -// look for the address part of a mail autolink and '>' -// this is less strict than the original markdown e-mail address matching -func isMailtoAutoLink(data []byte) int { - nb := 0 - - // address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' - for i := 0; i < len(data); i++ { - if isalnum(data[i]) { - continue - } - - switch data[i] { - case '@': - nb++ - - case '-', '.', '_': - break - - case '>': - if nb == 1 { - return i + 1 - } - return 0 - default: - return 0 - } - } - - return 0 -} - -// look for the next emph char, skipping other constructs -func helperFindEmphChar(data []byte, c byte) int { - i := 0 - - for i < len(data) { - for i < len(data) && data[i] != c && data[i] != '`' && data[i] != '[' { - i++ - } - if i >= len(data) { - return 0 - } - // do not count escaped chars - if i != 0 && data[i-1] == '\\' { - i++ - continue - } - if data[i] == c { - return i - } - - if data[i] == '`' { - // skip a code span - tmpI := 0 - i++ - for i < len(data) && data[i] != '`' { - if tmpI == 0 && data[i] == c { - tmpI = i - } - i++ - } - if i >= len(data) { - return tmpI - } - i++ - } else if data[i] == '[' { - // skip a link - tmpI := 0 - i++ - for i < len(data) && data[i] != ']' { - if tmpI == 0 && data[i] == c { - tmpI = i - } - i++ - } - i++ - for i < len(data) && (data[i] == ' ' || data[i] == '\n') { - i++ - } - if i >= len(data) { - return tmpI - } - if data[i] != '[' && data[i] != '(' { // not a link - if tmpI > 0 { - return tmpI - } - continue - } - cc := data[i] - i++ - for i < len(data) && data[i] != cc { - if tmpI == 0 && data[i] == c { - return i - } - i++ - } - if i >= len(data) { - return tmpI - } - i++ - } - } - return 0 -} - -func helperEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { - i := 0 - - // skip one symbol if coming from emph3 - if len(data) > 1 && data[0] == c && data[1] == c { - i = 1 - } - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - if i >= len(data) { - return 0, nil - } - - if i+1 < len(data) && data[i+1] == c { - i++ - continue - } - - if data[i] == c && !isspace(data[i-1]) { - - if p.extensions&NoIntraEmphasis != 0 { - if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) { - continue - } - } - - emph := NewNode(Emph) - p.inline(emph, data[:i]) - return i + 1, emph - } - } - - return 0, nil -} - -func helperDoubleEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { - i := 0 - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - - if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) { - nodeType := Strong - if c == '~' { - nodeType = Del - } - node := NewNode(nodeType) - p.inline(node, data[:i]) - return i + 2, node - } - i++ - } - return 0, nil -} - -func helperTripleEmphasis(p *Markdown, data []byte, offset int, c byte) (int, *Node) { - i := 0 - origData := data - data = data[offset:] - - for i < len(data) { - length := helperFindEmphChar(data[i:], c) - if length == 0 { - return 0, nil - } - i += length - - // skip whitespace preceded symbols - if data[i] != c || isspace(data[i-1]) { - continue - } - - switch { - case i+2 < len(data) && data[i+1] == c && data[i+2] == c: - // triple symbol found - strong := NewNode(Strong) - em := NewNode(Emph) - strong.AppendChild(em) - p.inline(em, data[:i]) - return i + 3, strong - case (i+1 < len(data) && data[i+1] == c): - // double symbol found, hand over to emph1 - length, node := helperEmphasis(p, origData[offset-2:], c) - if length == 0 { - return 0, nil - } - return length - 2, node - default: - // single symbol found, hand over to emph2 - length, node := helperDoubleEmphasis(p, origData[offset-1:], c) - if length == 0 { - return 0, nil - } - return length - 1, node - } - } - return 0, nil -} - -func text(s []byte) *Node { - node := NewNode(Text) - node.Literal = s - return node -} - -func normalizeURI(s []byte) []byte { - return s // TODO: implement -} diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/markdown.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/markdown.go deleted file mode 100644 index 4d0a831..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/markdown.go +++ /dev/null @@ -1,945 +0,0 @@ -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. - -//nolint:gocritic,wastedassign,unused,revive,govet // ignore blackfriday -package blackfriday - -import ( - "bytes" - "fmt" - "io" - "strings" - "unicode/utf8" -) - -// -// Markdown parsing and processing -// - -// Version string of the package. Appears in the rendered document when -// CompletePage flag is on. -const Version = "2.0" - -// Extensions is a bitwise or'ed collection of enabled Blackfriday's -// extensions. -type Extensions int - -// These are the supported markdown parsing extensions. -// OR these values together to select multiple extensions. -const ( - NoExtensions Extensions = 0 - NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words - Tables // Render tables - FencedCode // Render fenced code blocks - Autolink // Detect embedded URLs that are not explicitly marked - Strikethrough // Strikethrough text using ~~test~~ - LaxHTMLBlocks // Loosen up HTML block parsing rules - SpaceHeadings // Be strict about prefix heading rules - HardLineBreak // Translate newlines into line breaks - TabSizeEight // Expand tabs to eight spaces instead of four - Footnotes // Pandoc-style footnotes - NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block - HeadingIDs // specify heading IDs with {#id} - Titleblock // Titleblock ala pandoc - AutoHeadingIDs // Create the heading ID from the text - BackslashLineBreak // Translate trailing backslashes into line breaks - DefinitionLists // Render definition lists - - CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants | - SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes - - CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | - Autolink | Strikethrough | SpaceHeadings | HeadingIDs | - BackslashLineBreak | DefinitionLists -) - -// ListType contains bitwise or'ed flags for list and list item objects. -type ListType int - -// These are the possible flag values for the ListItem renderer. -// Multiple flag values may be ORed together. -// These are mostly of interest if you are writing a new output format. -const ( - ListTypeOrdered ListType = 1 << iota - ListTypeDefinition - ListTypeTerm - - ListItemContainsBlock - ListItemBeginningOfList // TODO: figure out if this is of any use now - ListItemEndOfList -) - -// CellAlignFlags holds a type of alignment in a table cell. -type CellAlignFlags int - -// These are the possible flag values for the table cell renderer. -// Only a single one of these values will be used; they are not ORed together. -// These are mostly of interest if you are writing a new output format. -const ( - TableAlignmentLeft CellAlignFlags = 1 << iota - TableAlignmentRight - TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight) -) - -// The size of a tab stop. -const ( - TabSizeDefault = 4 - TabSizeDouble = 8 -) - -// blockTags is a set of tags that are recognized as HTML block tags. -// Any of these can be included in markdown text without special escaping. -var blockTags = map[string]struct{}{ - "blockquote": {}, - "del": {}, - "div": {}, - "dl": {}, - "fieldset": {}, - "form": {}, - "h1": {}, - "h2": {}, - "h3": {}, - "h4": {}, - "h5": {}, - "h6": {}, - "iframe": {}, - "ins": {}, - "math": {}, - "noscript": {}, - "ol": {}, - "pre": {}, - "p": {}, - "script": {}, - "style": {}, - "table": {}, - "ul": {}, - - // HTML5 - "address": {}, - "article": {}, - "aside": {}, - "canvas": {}, - "figcaption": {}, - "figure": {}, - "footer": {}, - "header": {}, - "hgroup": {}, - "main": {}, - "nav": {}, - "output": {}, - "progress": {}, - "section": {}, - "video": {}, -} - -// Renderer is the rendering interface. This is mostly of interest if you are -// implementing a new rendering format. -// -// Only an HTML implementation is provided in this repository, see the README -// for external implementations. -type Renderer interface { - // RenderNode is the main rendering method. It will be called once for - // every leaf node and twice for every non-leaf node (first with - // entering=true, then with entering=false). The method should write its - // rendition of the node to the supplied writer w. - RenderNode(w io.Writer, node *Node, entering bool) WalkStatus - - // RenderHeader is a method that allows the renderer to produce some - // content preceding the main body of the output document. The header is - // understood in the broad sense here. For example, the default HTML - // renderer will write not only the HTML document preamble, but also the - // table of contents if it was requested. - // - // The method will be passed an entire document tree, in case a particular - // implementation needs to inspect it to produce output. - // - // The output should be written to the supplied writer w. If your - // implementation has no header to write, supply an empty implementation. - RenderHeader(w io.Writer, ast *Node) - - // RenderFooter is a symmetric counterpart of RenderHeader. - RenderFooter(w io.Writer, ast *Node) -} - -// Callback functions for inline parsing. One such function is defined -// for each character that triggers a response when parsing inline data. -type inlineParser func(p *Markdown, data []byte, offset int) (int, *Node) - -// Markdown is a type that holds extensions and the runtime state used by -// Parse, and the renderer. You can not use it directly, construct it with New. -type Markdown struct { - renderer Renderer - referenceOverride ReferenceOverrideFunc - refs map[string]*reference - inlineCallback [256]inlineParser - extensions Extensions - nesting int - maxNesting int - insideLink bool - - // Footnotes need to be ordered as well as available to quickly check for - // presence. If a ref is also a footnote, it's stored both in refs and here - // in notes. Slice is nil if footnotes not enabled. - notes []*reference - - doc *Node - tip *Node // = doc - oldTip *Node - lastMatchedContainer *Node // = doc - allClosed bool -} - -func (p *Markdown) getRef(refid string) (ref *reference, found bool) { - if p.referenceOverride != nil { - r, overridden := p.referenceOverride(refid) - if overridden { - if r == nil { - return nil, false - } - return &reference{ - link: []byte(r.Link), - title: []byte(r.Title), - noteID: 0, - hasBlock: false, - text: []byte(r.Text)}, true - } - } - // refs are case insensitive - ref, found = p.refs[strings.ToLower(refid)] - return ref, found -} - -func (p *Markdown) finalize(block *Node) { - above := block.Parent - block.open = false - p.tip = above -} - -func (p *Markdown) addChild(node NodeType, offset uint32) *Node { - return p.addExistingChild(NewNode(node), offset) -} - -func (p *Markdown) addExistingChild(node *Node, offset uint32) *Node { - for !p.tip.canContain(node.Type) { - p.finalize(p.tip) - } - p.tip.AppendChild(node) - p.tip = node - return node -} - -func (p *Markdown) closeUnmatchedBlocks() { - if !p.allClosed { - for p.oldTip != p.lastMatchedContainer { - parent := p.oldTip.Parent - p.finalize(p.oldTip) - p.oldTip = parent - } - p.allClosed = true - } -} - -// -// -// Public interface -// -// - -// Reference represents the details of a link. -// See the documentation in Options for more details on use-case. -type Reference struct { - // Link is usually the URL the reference points to. - Link string - // Title is the alternate text describing the link in more detail. - Title string - // Text is the optional text to override the ref with if the syntax used was - // [refid][] - Text string -} - -// ReferenceOverrideFunc is expected to be called with a reference string and -// return either a valid Reference type that the reference string maps to or -// nil. If overridden is false, the default reference logic will be executed. -// See the documentation in Options for more details on use-case. -type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool) - -// New constructs a Markdown processor. You can use the same With* functions as -// for Run() to customize parser's behavior and the renderer. -func New(opts ...Option) *Markdown { - var p Markdown - for _, opt := range opts { - opt(&p) - } - p.refs = make(map[string]*reference) - p.maxNesting = 16 - p.insideLink = false - docNode := NewNode(Document) - p.doc = docNode - p.tip = docNode - p.oldTip = docNode - p.lastMatchedContainer = docNode - p.allClosed = true - // register inline parsers - p.inlineCallback[' '] = maybeLineBreak - p.inlineCallback['*'] = emphasis - p.inlineCallback['_'] = emphasis - if p.extensions&Strikethrough != 0 { - p.inlineCallback['~'] = emphasis - } - p.inlineCallback['`'] = codeSpan - p.inlineCallback['\n'] = lineBreak - p.inlineCallback['['] = link - p.inlineCallback['<'] = leftAngle - p.inlineCallback['\\'] = escape - p.inlineCallback['&'] = entity - p.inlineCallback['!'] = maybeImage - p.inlineCallback['^'] = maybeInlineFootnote - if p.extensions&Autolink != 0 { - p.inlineCallback['h'] = maybeAutoLink - p.inlineCallback['m'] = maybeAutoLink - p.inlineCallback['f'] = maybeAutoLink - p.inlineCallback['H'] = maybeAutoLink - p.inlineCallback['M'] = maybeAutoLink - p.inlineCallback['F'] = maybeAutoLink - } - if p.extensions&Footnotes != 0 { - p.notes = make([]*reference, 0) - } - return &p -} - -// Option customizes the Markdown processor's default behavior. -type Option func(*Markdown) - -// WithRenderer allows you to override the default renderer. -func WithRenderer(r Renderer) Option { - return func(p *Markdown) { - p.renderer = r - } -} - -// WithExtensions allows you to pick some of the many extensions provided by -// Blackfriday. You can bitwise OR them. -func WithExtensions(e Extensions) Option { - return func(p *Markdown) { - p.extensions = e - } -} - -// WithNoExtensions turns off all extensions and custom behavior. -func WithNoExtensions() Option { - return func(p *Markdown) { - p.extensions = NoExtensions - p.renderer = NewHTMLRenderer(HTMLRendererParameters{ - Flags: HTMLFlagsNone, - }) - } -} - -// WithRefOverride sets an optional function callback that is called every -// time a reference is resolved. -// -// In Markdown, the link reference syntax can be made to resolve a link to -// a reference instead of an inline URL, in one of the following ways: -// -// - [link text][refid] -// - [refid][] -// -// Usually, the refid is defined at the bottom of the Markdown document. If -// this override function is provided, the refid is passed to the override -// function first, before consulting the defined refids at the bottom. If -// the override function indicates an override did not occur, the refids at -// the bottom will be used to fill in the link details. -func WithRefOverride(o ReferenceOverrideFunc) Option { - return func(p *Markdown) { - p.referenceOverride = o - } -} - -// Run is the main entry point to Blackfriday. It parses and renders a -// block of markdown-encoded text. -// -// The simplest invocation of Run takes one argument, input: -// -// output := Run(input) -// -// This will parse the input with CommonExtensions enabled and render it with -// the default HTMLRenderer (with CommonHTMLFlags). -// -// Variadic arguments opts can customize the default behavior. Since Markdown -// type does not contain exported fields, you can not use it directly. Instead, -// use the With* functions. For example, this will call the most basic -// functionality, with no extensions: -// -// output := Run(input, WithNoExtensions()) -// -// You can use any number of With* arguments, even contradicting ones. They -// will be applied in order of appearance and the latter will override the -// former: -// -// output := Run(input, WithNoExtensions(), WithExtensions(exts), -// WithRenderer(yourRenderer)) -func Run(input []byte, opts ...Option) []byte { - r := NewHTMLRenderer(HTMLRendererParameters{ - Flags: CommonHTMLFlags, - }) - optList := []Option{WithRenderer(r), WithExtensions(CommonExtensions)} - optList = append(optList, opts...) - parser := New(optList...) - ast := parser.Parse(input) - var buf bytes.Buffer - parser.renderer.RenderHeader(&buf, ast) - ast.Walk(func(node *Node, entering bool) WalkStatus { - return parser.renderer.RenderNode(&buf, node, entering) - }) - parser.renderer.RenderFooter(&buf, ast) - return buf.Bytes() -} - -// Parse is an entry point to the parsing part of Blackfriday. It takes an -// input markdown document and produces a syntax tree for its contents. This -// tree can then be rendered with a default or custom renderer, or -// analyzed/transformed by the caller to whatever non-standard needs they have. -// The return value is the root node of the syntax tree. -func (p *Markdown) Parse(input []byte) *Node { - p.block(input) - // Walk the tree and finish up some of unfinished blocks - for p.tip != nil { - p.finalize(p.tip) - } - // Walk the tree again and process inline markdown in each block - p.doc.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Paragraph || node.Type == Heading || node.Type == TableCell { - p.inline(node, node.content) - node.content = nil - } - return GoToNext - }) - p.parseRefsToAST() - return p.doc -} - -func (p *Markdown) parseRefsToAST() { - if p.extensions&Footnotes == 0 || len(p.notes) == 0 { - return - } - p.tip = p.doc - block := p.addBlock(List, nil) - block.IsFootnotesList = true - block.ListFlags = ListTypeOrdered - flags := ListItemBeginningOfList - // Note: this loop is intentionally explicit, not range-form. This is - // because the body of the loop will append nested footnotes to p.notes and - // we need to process those late additions. Range form would only walk over - // the fixed initial set. - for i := 0; i < len(p.notes); i++ { - ref := p.notes[i] - p.addExistingChild(ref.footnote, 0) - block := ref.footnote - block.ListFlags = flags | ListTypeOrdered - block.RefLink = ref.link - if ref.hasBlock { - flags |= ListItemContainsBlock - p.block(ref.title) - } else { - p.inline(block, ref.title) - } - flags &^= ListItemBeginningOfList | ListItemContainsBlock - } - above := block.Parent - finalizeList(block) - p.tip = above - block.Walk(func(node *Node, entering bool) WalkStatus { - if node.Type == Paragraph || node.Type == Heading { - p.inline(node, node.content) - node.content = nil - } - return GoToNext - }) -} - -// -// Link references -// -// This section implements support for references that (usually) appear -// as footnotes in a document, and can be referenced anywhere in the document. -// The basic format is: -// -// [1]: http://www.google.com/ "Google" -// [2]: http://www.github.com/ "Github" -// -// Anywhere in the document, the reference can be linked by referring to its -// label, i.e., 1 and 2 in this example, as in: -// -// This library is hosted on [Github][2], a git hosting site. -// -// Actual footnotes as specified in Pandoc and supported by some other Markdown -// libraries such as php-markdown are also taken care of. They look like this: -// -// This sentence needs a bit of further explanation.[^note] -// -// [^note]: This is the explanation. -// -// Footnotes should be placed at the end of the document in an ordered list. -// Inline footnotes such as: -// -// Inline footnotes^[Not supported.] also exist. -// -// are not yet supported. - -// reference holds all information necessary for a reference-style links or -// footnotes. -// -// Consider this markdown with reference-style links: -// -// [link][ref] -// -// [ref]: /url/ "tooltip title" -// -// It will be ultimately converted to this HTML: -// -// <p><a href=\"/url/\" title=\"title\">link</a></p> -// -// And a reference structure will be populated as follows: -// -// p.refs["ref"] = &reference{ -// link: "/url/", -// title: "tooltip title", -// } -// -// Alternatively, reference can contain information about a footnote. Consider -// this markdown: -// -// Text needing a footnote.[^a] -// -// [^a]: This is the note -// -// A reference structure will be populated as follows: -// -// p.refs["a"] = &reference{ -// link: "a", -// title: "This is the note", -// noteID: <some positive int>, -// } -// -// TODO: As you can see, it begs for splitting into two dedicated structures -// for refs and for footnotes. -type reference struct { - link []byte - title []byte - noteID int // 0 if not a footnote ref - hasBlock bool - footnote *Node // a link to the Item node within a list of footnotes - - text []byte // only gets populated by refOverride feature with Reference.Text -} - -func (r *reference) String() string { - return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}", - r.link, r.title, r.text, r.noteID, r.hasBlock) -} - -// Check whether or not data starts with a reference link. -// If so, it is parsed and stored in the list of references -// (in the render struct). -// Returns the number of bytes to skip to move past it, -// or zero if the first line is not a reference. -func isReference(p *Markdown, data []byte, tabSize int) int { - // up to 3 optional leading spaces - if len(data) < 4 { - return 0 - } - i := 0 - for i < 3 && data[i] == ' ' { - i++ - } - - noteID := 0 - - // id part: anything but a newline between brackets - if data[i] != '[' { - return 0 - } - i++ - if p.extensions&Footnotes != 0 { - if i < len(data) && data[i] == '^' { - // we can set it to anything here because the proper noteIds will - // be assigned later during the second pass. It just has to be != 0 - noteID = 1 - i++ - } - } - idOffset := i - for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' { - i++ - } - if i >= len(data) || data[i] != ']' { - return 0 - } - idEnd := i - // footnotes can have empty ID, like this: [^], but a reference can not be - // empty like this: []. Break early if it's not a footnote and there's no ID - if noteID == 0 && idOffset == idEnd { - return 0 - } - // spacer: colon (space | tab)* newline? (space | tab)* - i++ - if i >= len(data) || data[i] != ':' { - return 0 - } - i++ - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i < len(data) && (data[i] == '\n' || data[i] == '\r') { - i++ - if i < len(data) && data[i] == '\n' && data[i-1] == '\r' { - i++ - } - } - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i >= len(data) { - return 0 - } - - var ( - linkOffset, linkEnd int - titleOffset, titleEnd int - lineEnd int - raw []byte - hasBlock bool - ) - - if p.extensions&Footnotes != 0 && noteID != 0 { - linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize) - lineEnd = linkEnd - } else { - linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i) - } - if lineEnd == 0 { - return 0 - } - - // a valid ref has been found - - ref := &reference{ - noteID: noteID, - hasBlock: hasBlock, - } - - if noteID > 0 { - // reusing the link field for the id since footnotes don't have links - ref.link = data[idOffset:idEnd] - // if footnote, it's not really a title, it's the contained text - ref.title = raw - } else { - ref.link = data[linkOffset:linkEnd] - ref.title = data[titleOffset:titleEnd] - } - - // id matches are case-insensitive - id := string(bytes.ToLower(data[idOffset:idEnd])) - - p.refs[id] = ref - - return lineEnd -} - -func scanLinkRef(p *Markdown, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) { - // link: whitespace-free sequence, optionally between angle brackets - if data[i] == '<' { - i++ - } - linkOffset = i - for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' { - i++ - } - linkEnd = i - if data[linkOffset] == '<' && data[linkEnd-1] == '>' { - linkOffset++ - linkEnd-- - } - - // optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' { - return - } - - // compute end-of-line - if i >= len(data) || data[i] == '\r' || data[i] == '\n' { - lineEnd = i - } - if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' { - lineEnd++ - } - - // optional (space|tab)* spacer after a newline - if lineEnd > 0 { - i = lineEnd + 1 - for i < len(data) && (data[i] == ' ' || data[i] == '\t') { - i++ - } - } - - // optional title: any non-newline sequence enclosed in '"() alone on its line - if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') { - i++ - titleOffset = i - - // look for EOL - for i < len(data) && data[i] != '\n' && data[i] != '\r' { - i++ - } - if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' { - titleEnd = i + 1 - } else { - titleEnd = i - } - - // step back - i-- - for i > titleOffset && (data[i] == ' ' || data[i] == '\t') { - i-- - } - if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') { - lineEnd = titleEnd - titleEnd = i - } - } - - return -} - -// The first bit of this logic is the same as Parser.listItem, but the rest -// is much simpler. This function simply finds the entire block and shifts it -// over by one tab if it is indeed a block (just returns the line if it's not). -// blockEnd is the end of the section in the input buffer, and contents is the -// extracted text that was shifted over one tab. It will need to be rendered at -// the end of the document. -func scanFootnote(p *Markdown, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) { - if i == 0 || len(data) == 0 { - return - } - - // skip leading whitespace on first line - for i < len(data) && data[i] == ' ' { - i++ - } - - blockStart = i - - // find the end of the line - blockEnd = i - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // get working buffer - var raw bytes.Buffer - - // put the first line into the working buffer - raw.Write(data[blockEnd:i]) - blockEnd = i - - // process the following lines - containsBlankLine := false - -gatherLines: - for blockEnd < len(data) { - i++ - - // find the end of this line - for i < len(data) && data[i-1] != '\n' { - i++ - } - - // if it is an empty line, guess that it is part of this item - // and move on to the next line - if p.isEmpty(data[blockEnd:i]) > 0 { - containsBlankLine = true - blockEnd = i - continue - } - - n := 0 - if n = isIndented(data[blockEnd:i], indentSize); n == 0 { - // this is the end of the block. - // we don't want to include this last line in the index. - break gatherLines - } - - // if there were blank lines before this one, insert a new one now - if containsBlankLine { - raw.WriteByte('\n') - containsBlankLine = false - } - - // get rid of that first tab, write to buffer - raw.Write(data[blockEnd+n : i]) - hasBlock = true - - blockEnd = i - } - - if data[blockEnd-1] != '\n' { - raw.WriteByte('\n') - } - - contents = raw.Bytes() - - return -} - -// -// -// Miscellaneous helper functions -// -// - -// Test if a character is a punctuation symbol. -// Taken from a private function in regexp in the stdlib. -func ispunct(c byte) bool { - for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") { - if c == r { - return true - } - } - return false -} - -// Test if a character is a whitespace character. -func isspace(c byte) bool { - return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' -} - -// Test if a character is letter. -func isletter(c byte) bool { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') -} - -// Test if a character is a letter or a digit. -// TODO: check when this is looking for ASCII alnum and when it should use unicode -func isalnum(c byte) bool { - return (c >= '0' && c <= '9') || isletter(c) -} - -// Replace tab characters with spaces, aligning to the next TAB_SIZE column. -// always ends output with a newline -func expandTabs(out *bytes.Buffer, line []byte, tabSize int) { - // first, check for common cases: no tabs, or only tabs at beginning of line - i, prefix := 0, 0 - slowcase := false - for i = 0; i < len(line); i++ { - if line[i] == '\t' { - if prefix == i { - prefix++ - } else { - slowcase = true - break - } - } - } - - // no need to decode runes if all tabs are at the beginning of the line - if !slowcase { - for i = 0; i < prefix*tabSize; i++ { - out.WriteByte(' ') - } - out.Write(line[prefix:]) - return - } - - // the slow case: we need to count runes to figure out how - // many spaces to insert for each tab - column := 0 - i = 0 - for i < len(line) { - start := i - for i < len(line) && line[i] != '\t' { - _, size := utf8.DecodeRune(line[i:]) - i += size - column++ - } - - if i > start { - out.Write(line[start:i]) - } - - if i >= len(line) { - break - } - - for { - out.WriteByte(' ') - column++ - if column%tabSize == 0 { - break - } - } - - i++ - } -} - -// Find if a line counts as indented or not. -// Returns number of characters the indent is (0 = not indented). -func isIndented(data []byte, indentSize int) int { - if len(data) == 0 { - return 0 - } - if data[0] == '\t' { - return 1 - } - if len(data) < indentSize { - return 0 - } - for i := 0; i < indentSize; i++ { - if data[i] != ' ' { - return 0 - } - } - return indentSize -} - -// Create a url-safe slug for fragments -func slugify(in []byte) []byte { - if len(in) == 0 { - return in - } - out := make([]byte, 0, len(in)) - sym := false - - for _, ch := range in { - if isalnum(ch) { - sym = false - out = append(out, ch) - } else if sym { - continue - } else { - out = append(out, '-') - sym = true - } - } - var a, b int - var ch byte - for a, ch = range out { - if ch != '-' { - break - } - } - for b = len(out) - 1; b > 0; b-- { - if out[b] != '-' { - break - } - } - return out[a : b+1] -} diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/node.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/node.go deleted file mode 100644 index d820b83..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/node.go +++ /dev/null @@ -1,355 +0,0 @@ -//nolint:gocritic,unused // ignore blackfriday -package blackfriday - -import ( - "bytes" - "fmt" -) - -// NodeType specifies a type of a single node of a syntax tree. Usually one -// node (and its type) corresponds to a single markdown feature, e.g. emphasis -// or code block. -type NodeType int - -// Constants for identifying different types of nodes. See NodeType. -const ( - Document NodeType = iota - BlockQuote - List - Item - Paragraph - Heading - HorizontalRule - Emph - Strong - Del - Link - Image - Text - HTMLBlock - CodeBlock - Softbreak - Hardbreak - Code - HTMLSpan - Table - TableCell - TableHead - TableBody - TableRow -) - -var nodeTypeNames = []string{ - Document: "Document", - BlockQuote: "BlockQuote", - List: "List", - Item: "Item", - Paragraph: "Paragraph", - Heading: "Heading", - HorizontalRule: "HorizontalRule", - Emph: "Emph", - Strong: "Strong", - Del: "Del", - Link: "Link", - Image: "Image", - Text: "Text", - HTMLBlock: "HTMLBlock", - CodeBlock: "CodeBlock", - Softbreak: "Softbreak", - Hardbreak: "Hardbreak", - Code: "Code", - HTMLSpan: "HTMLSpan", - Table: "Table", - TableCell: "TableCell", - TableHead: "TableHead", - TableBody: "TableBody", - TableRow: "TableRow", -} - -func (t NodeType) String() string { - return nodeTypeNames[t] -} - -// ListData contains fields relevant to a List and Item node type. -type ListData struct { - ListFlags ListType - Tight bool // Skip <p>s around list item data if true - BulletChar byte // '*', '+' or '-' in bullet lists - Delimiter byte // '.' or ')' after the number in ordered lists - RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering - IsFootnotesList bool // This is a list of footnotes -} - -// LinkData contains fields relevant to a Link node type. -type LinkData struct { - Destination []byte // Destination is what goes into a href - Title []byte // Title is the tooltip thing that goes in a title attribute - NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote - Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil. -} - -// CodeBlockData contains fields relevant to a CodeBlock node type. -type CodeBlockData struct { - IsFenced bool // Specifies whether it's a fenced code block or an indented one - Info []byte // This holds the info string - FenceChar byte - FenceLength int - FenceOffset int -} - -// TableCellData contains fields relevant to a TableCell node type. -type TableCellData struct { - IsHeader bool // This tells if it's under the header row - Align CellAlignFlags // This holds the value for align attribute -} - -// HeadingData contains fields relevant to a Heading node type. -type HeadingData struct { - Level int // This holds the heading level number - HeadingID string // This might hold heading ID, if present - IsTitleblock bool // Specifies whether it's a title block -} - -// Node is a single element in the abstract syntax tree of the parsed document. -// It holds connections to the structurally neighboring nodes and, for certain -// types of nodes, additional information that might be needed when rendering. -type Node struct { - Type NodeType // Determines the type of the node - Parent *Node // Points to the parent - FirstChild *Node // Points to the first child, if any - LastChild *Node // Points to the last child, if any - Prev *Node // Previous sibling; nil if it's the first child - Next *Node // Next sibling; nil if it's the last child - - Literal []byte // Text contents of the leaf nodes - - HeadingData // Populated if Type is Heading - ListData // Populated if Type is List - CodeBlockData // Populated if Type is CodeBlock - LinkData // Populated if Type is Link - TableCellData // Populated if Type is TableCell - - content []byte // Markdown content of the block nodes - open bool // Specifies an open block node that has not been finished to process yet -} - -// NewNode allocates a node of a specified type. -func NewNode(typ NodeType) *Node { - return &Node{ - Type: typ, - open: true, - } -} - -func (n *Node) String() string { - ellipsis := "" - snippet := n.Literal - if len(snippet) > 16 { - snippet = snippet[:16] - ellipsis = "..." - } - return fmt.Sprintf("%s: '%s%s'", n.Type, snippet, ellipsis) -} - -// Unlink removes node 'n' from the tree. -// It panics if the node is nil. -func (n *Node) Unlink() { - if n.Prev != nil { - n.Prev.Next = n.Next - } else if n.Parent != nil { - n.Parent.FirstChild = n.Next - } - if n.Next != nil { - n.Next.Prev = n.Prev - } else if n.Parent != nil { - n.Parent.LastChild = n.Prev - } - n.Parent = nil - n.Next = nil - n.Prev = nil -} - -// AppendChild adds a node 'child' as a child of 'n'. -// It panics if either node is nil. -func (n *Node) AppendChild(child *Node) { - child.Unlink() - child.Parent = n - if n.LastChild != nil { - n.LastChild.Next = child - child.Prev = n.LastChild - n.LastChild = child - } else { - n.FirstChild = child - n.LastChild = child - } -} - -// InsertBefore inserts 'sibling' immediately before 'n'. -// It panics if either node is nil. -func (n *Node) InsertBefore(sibling *Node) { - sibling.Unlink() - sibling.Prev = n.Prev - if sibling.Prev != nil { - sibling.Prev.Next = sibling - } - sibling.Next = n - n.Prev = sibling - sibling.Parent = n.Parent - if sibling.Prev == nil { - sibling.Parent.FirstChild = sibling - } -} - -func (n *Node) isContainer() bool { - switch n.Type { - case Document: - fallthrough - case BlockQuote: - fallthrough - case List: - fallthrough - case Item: - fallthrough - case Paragraph: - fallthrough - case Heading: - fallthrough - case Emph: - fallthrough - case Strong: - fallthrough - case Del: - fallthrough - case Link: - fallthrough - case Image: - fallthrough - case Table: - fallthrough - case TableHead: - fallthrough - case TableBody: - fallthrough - case TableRow: - fallthrough - case TableCell: - return true - default: - return false - } -} - -func (n *Node) canContain(t NodeType) bool { - if n.Type == List { - return t == Item - } - if n.Type == Document || n.Type == BlockQuote || n.Type == Item { - return t != Item - } - if n.Type == Table { - return t == TableHead || t == TableBody - } - if n.Type == TableHead || n.Type == TableBody { - return t == TableRow - } - if n.Type == TableRow { - return t == TableCell - } - return false -} - -// WalkStatus allows NodeVisitor to have some control over the tree traversal. -// It is returned from NodeVisitor and different values allow Node.Walk to -// decide which node to go to next. -type WalkStatus int - -const ( - // GoToNext is the default traversal of every node. - GoToNext WalkStatus = iota - // SkipChildren tells walker to skip all children of current node. - SkipChildren - // Terminate tells walker to terminate the traversal. - Terminate -) - -// NodeVisitor is a callback to be called when traversing the syntax tree. -// Called twice for every node: once with entering=true when the branch is -// first visited, then with entering=false after all the children are done. -type NodeVisitor func(node *Node, entering bool) WalkStatus - -// Walk is a convenience method that instantiates a walker and starts a -// traversal of subtree rooted at n. -func (n *Node) Walk(visitor NodeVisitor) { - w := newNodeWalker(n) - for w.current != nil { - status := visitor(w.current, w.entering) - switch status { - case GoToNext: - w.next() - case SkipChildren: - w.entering = false - w.next() - case Terminate: - return - } - } -} - -type nodeWalker struct { - current *Node - root *Node - entering bool -} - -func newNodeWalker(root *Node) *nodeWalker { - return &nodeWalker{ - current: root, - root: root, - entering: true, - } -} - -func (nw *nodeWalker) next() { - if (!nw.current.isContainer() || !nw.entering) && nw.current == nw.root { - nw.current = nil - return - } - if nw.entering && nw.current.isContainer() { - if nw.current.FirstChild != nil { - nw.current = nw.current.FirstChild - nw.entering = true - } else { - nw.entering = false - } - } else if nw.current.Next == nil { - nw.current = nw.current.Parent - nw.entering = false - } else { - nw.current = nw.current.Next - nw.entering = true - } -} - -func dump(ast *Node) { - fmt.Println(dumpString(ast)) -} - -func dumpR(ast *Node, depth int) string { - if ast == nil { - return "" - } - indent := bytes.Repeat([]byte("\t"), depth) - content := ast.Literal - if content == nil { - content = ast.content - } - result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content) - for n := ast.FirstChild; n != nil; n = n.Next { - result += dumpR(n, depth+1) - } - return result -} - -func dumpString(ast *Node) string { - return dumpR(ast, 0) -} diff --git a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/smartypants.go b/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/smartypants.go deleted file mode 100644 index e5f9e19..0000000 --- a/vendor/github.com/smallstep/cli-utils/pkg/blackfriday/smartypants.go +++ /dev/null @@ -1,458 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross <russ@russross.com>. -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// -// SmartyPants rendering -// -// - -//nolint:gocritic,revive // ignore blackfriday -package blackfriday - -import ( - "bytes" - "io" -) - -// SPRenderer is a struct containing state of a Smartypants renderer. -type SPRenderer struct { - inSingleQuote bool - inDoubleQuote bool - callbacks [256]smartCallback -} - -func wordBoundary(c byte) bool { - return c == 0 || isspace(c) || ispunct(c) -} - -func tolower(c byte) byte { - if c >= 'A' && c <= 'Z' { - return c - 'A' + 'a' - } - return c -} - -func isdigit(c byte) bool { - return c >= '0' && c <= '9' -} - -func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool, addNBSP bool) bool { - // edge of the buffer is likely to be a tag that we don't get to see, - // so we treat it like text sometimes - - // enumerate all sixteen possibilities for (previousChar, nextChar) - // each can be one of {0, space, punct, other} - switch { - case previousChar == 0 && nextChar == 0: - // context is not any help here, so toggle - *isOpen = !*isOpen - case isspace(previousChar) && nextChar == 0: - // [ "] might be [ "<code>foo...] - *isOpen = true - case ispunct(previousChar) && nextChar == 0: - // [!"] hmm... could be [Run!"] or [("<code>...] - *isOpen = false - case /* isnormal(previousChar) && */ nextChar == 0: - // [a"] is probably a close - *isOpen = false - case previousChar == 0 && isspace(nextChar): - // [" ] might be [...foo</code>" ] - *isOpen = false - case isspace(previousChar) && isspace(nextChar): - // [ " ] context is not any help here, so toggle - *isOpen = !*isOpen - case ispunct(previousChar) && isspace(nextChar): - // [!" ] is probably a close - *isOpen = false - case /* isnormal(previousChar) && */ isspace(nextChar): - // [a" ] this is one of the easy cases - *isOpen = false - case previousChar == 0 && ispunct(nextChar): - // ["!] hmm... could be ["$1.95] or [</code>"!...] - *isOpen = false - case isspace(previousChar) && ispunct(nextChar): - // [ "!] looks more like [ "$1.95] - *isOpen = true - case ispunct(previousChar) && ispunct(nextChar): - // [!"!] context is not any help here, so toggle - *isOpen = !*isOpen - case /* isnormal(previousChar) && */ ispunct(nextChar): - // [a"!] is probably a close - *isOpen = false - case previousChar == 0 /* && isnormal(nextChar) */ : - // ["a] is probably an open - *isOpen = true - case isspace(previousChar) /* && isnormal(nextChar) */ : - // [ "a] this is one of the easy cases - *isOpen = true - case ispunct(previousChar) /* && isnormal(nextChar) */ : - // [!"a] is probably an open - *isOpen = true - default: - // [a'b] maybe a contraction? - *isOpen = false - } - - // Note that with the limited lookahead, this non-breaking - // space will also be appended to single double quotes. - if addNBSP && !*isOpen { - out.WriteString(" ") - } - - out.WriteByte('&') - if *isOpen { - out.WriteByte('l') - } else { - out.WriteByte('r') - } - out.WriteByte(quote) - out.WriteString("quo;") - - if addNBSP && *isOpen { - out.WriteString(" ") - } - - return true -} - -func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 { - t1 := tolower(text[1]) - - if t1 == '\'' { - nextChar := byte(0) - if len(text) >= 3 { - nextChar = text[2] - } - if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { - return 1 - } - } - - if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) { - out.WriteString("’") - return 0 - } - - if len(text) >= 3 { - t2 := tolower(text[2]) - - if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) && - (len(text) < 4 || wordBoundary(text[3])) { - out.WriteString("’") - return 0 - } - } - } - - nextChar := byte(0) - if len(text) > 1 { - nextChar = text[1] - } - if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote, false) { - return 0 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 { - t1 := tolower(text[1]) - t2 := tolower(text[2]) - - if t1 == 'c' && t2 == ')' { - out.WriteString("©") - return 2 - } - - if t1 == 'r' && t2 == ')' { - out.WriteString("®") - return 2 - } - - if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' { - out.WriteString("™") - return 3 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 { - if text[1] == '-' { - out.WriteString("—") - return 1 - } - - if wordBoundary(previousChar) && wordBoundary(text[1]) { - out.WriteString("–") - return 0 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 && text[1] == '-' && text[2] == '-' { - out.WriteString("—") - return 2 - } - if len(text) >= 2 && text[1] == '-' { - out.WriteString("–") - return 1 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte, addNBSP bool) int { - if bytes.HasPrefix(text, []byte(""")) { - nextChar := byte(0) - if len(text) >= 7 { - nextChar = text[6] - } - if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, addNBSP) { - return 5 - } - } - - if bytes.HasPrefix(text, []byte("�")) { - return 3 - } - - out.WriteByte('&') - return 0 -} - -func (r *SPRenderer) smartAmp(angledQuotes, addNBSP bool) func(*bytes.Buffer, byte, []byte) int { - var quote byte = 'd' - if angledQuotes { - quote = 'a' - } - - return func(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartAmpVariant(out, previousChar, text, quote, addNBSP) - } -} - -func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 3 && text[1] == '.' && text[2] == '.' { - out.WriteString("…") - return 2 - } - - if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' { - out.WriteString("…") - return 4 - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int { - if len(text) >= 2 && text[1] == '`' { - nextChar := byte(0) - if len(text) >= 3 { - nextChar = text[2] - } - if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { - return 1 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int { - if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { - // is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b - // note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8) - // and avoid changing dates like 1/23/2005 into fractions. - numEnd := 0 - for len(text) > numEnd && isdigit(text[numEnd]) { - numEnd++ - } - if numEnd == 0 { - out.WriteByte(text[0]) - return 0 - } - denStart := numEnd + 1 - if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 { - denStart = numEnd + 3 - } else if len(text) < numEnd+2 || text[numEnd] != '/' { - out.WriteByte(text[0]) - return 0 - } - denEnd := denStart - for len(text) > denEnd && isdigit(text[denEnd]) { - denEnd++ - } - if denEnd == denStart { - out.WriteByte(text[0]) - return 0 - } - if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' { - out.WriteString("<sup>") - out.Write(text[:numEnd]) - out.WriteString("</sup>⁄<sub>") - out.Write(text[denStart:denEnd]) - out.WriteString("</sub>") - return denEnd - 1 - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int { - if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { - if text[0] == '1' && text[1] == '/' && text[2] == '2' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' { - out.WriteString("½") - return 2 - } - } - - if text[0] == '1' && text[1] == '/' && text[2] == '4' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') { - out.WriteString("¼") - return 2 - } - } - - if text[0] == '3' && text[1] == '/' && text[2] == '4' { - if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') { - out.WriteString("¾") - return 2 - } - } - } - - out.WriteByte(text[0]) - return 0 -} - -func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int { - nextChar := byte(0) - if len(text) > 1 { - nextChar = text[1] - } - if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, false) { - out.WriteString(""") - } - - return 0 -} - -func (r *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartDoubleQuoteVariant(out, previousChar, text, 'd') -} - -func (r *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { - return r.smartDoubleQuoteVariant(out, previousChar, text, 'a') -} - -func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int { - i := 0 - - for i < len(text) && text[i] != '>' { - i++ - } - - out.Write(text[:i+1]) - return i -} - -type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int - -// NewSmartypantsRenderer constructs a Smartypants renderer object. -func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer { - var ( - r SPRenderer - - smartAmpAngled = r.smartAmp(true, false) - smartAmpAngledNBSP = r.smartAmp(true, true) - smartAmpRegular = r.smartAmp(false, false) - smartAmpRegularNBSP = r.smartAmp(false, true) - - addNBSP = flags&SmartypantsQuotesNBSP != 0 - ) - - if flags&SmartypantsAngledQuotes == 0 { - r.callbacks['"'] = r.smartDoubleQuote - if !addNBSP { - r.callbacks['&'] = smartAmpRegular - } else { - r.callbacks['&'] = smartAmpRegularNBSP - } - } else { - r.callbacks['"'] = r.smartAngledDoubleQuote - if !addNBSP { - r.callbacks['&'] = smartAmpAngled - } else { - r.callbacks['&'] = smartAmpAngledNBSP - } - } - r.callbacks['\''] = r.smartSingleQuote - r.callbacks['('] = r.smartParens - if flags&SmartypantsDashes != 0 { - if flags&SmartypantsLatexDashes == 0 { - r.callbacks['-'] = r.smartDash - } else { - r.callbacks['-'] = r.smartDashLatex - } - } - r.callbacks['.'] = r.smartPeriod - if flags&SmartypantsFractions == 0 { - r.callbacks['1'] = r.smartNumber - r.callbacks['3'] = r.smartNumber - } else { - for ch := '1'; ch <= '9'; ch++ { - r.callbacks[ch] = r.smartNumberGeneric - } - } - r.callbacks['<'] = r.smartLeftAngle - r.callbacks['`'] = r.smartBacktick - return &r -} - -// Process is the entry point of the Smartypants renderer. -func (r *SPRenderer) Process(w io.Writer, text []byte) { - mark := 0 - for i := 0; i < len(text); i++ { - if action := r.callbacks[text[i]]; action != nil { - if i > mark { - w.Write(text[mark:i]) - } - previousChar := byte(0) - if i > 0 { - previousChar = text[i-1] - } - var tmp bytes.Buffer - i += action(&tmp, previousChar, text[i:]) - w.Write(tmp.Bytes()) - mark = i + 1 - } - } - if mark < len(text) { - w.Write(text[mark:]) - } -} diff --git a/vendor/github.com/smallstep/cli-utils/step/config.go b/vendor/github.com/smallstep/cli-utils/step/config.go deleted file mode 100644 index 269f21a..0000000 --- a/vendor/github.com/smallstep/cli-utils/step/config.go +++ /dev/null @@ -1,220 +0,0 @@ -package step - -import ( - "fmt" - "os" - "os/user" - "path/filepath" - "runtime" - "strings" - "sync" - "time" -) - -// PathEnv defines the name of the environment variable that can overwrite -// the default configuration path. -const PathEnv = "STEPPATH" - -// HomeEnv defines the name of the environment variable that can overwrite the -// default home directory. -const HomeEnv = "HOME" - -var ( - // version and buildTime are filled in during build by the Makefile - name = "Smallstep CLI" - buildTime = "N/A" - version = "N/A" -) - -var cache struct { - sync.Once - err error - stepBasePath string // stepBasePath will be populated in init() with the proper STEPPATH. - homePath string // homePath will be populated in init() with the proper HOME. -} - -// Init initializes the step environment. -// -// A program calling this function should fail because the step variables would -// be undefined. -func Init() error { - if err := initStepPath(); err != nil { - return err - } - return Contexts().Init() -} - -func initStepPath() error { - cache.Do(func() { - // Get home path from environment or from the user object. - homePath := os.Getenv(HomeEnv) - if homePath == "" { - usr, err := user.Current() - if err == nil && usr.HomeDir != "" { - homePath = usr.HomeDir - } else { - cache.err = fmt.Errorf("error obtaining home directory, please define environment variable %s", HomeEnv) - return - } - } - - // Get step path from environment or relative to home. - stepBasePath := os.Getenv(PathEnv) - if stepBasePath == "" { - stepBasePath = filepath.Join(homePath, ".step") - } - - // cleanup and add paths to cache - cache.homePath = filepath.Clean(homePath) - cache.stepBasePath = filepath.Clean(stepBasePath) - }) - - return cache.err -} - -// Home returns the user home directory using the environment variable HOME or -// the os/user package. -func Home() string { - _ = initStepPath() - return cache.homePath -} - -// BasePath returns the base path for the step configuration directory. -func BasePath() string { - _ = initStepPath() - return cache.stepBasePath -} - -// Path returns the path for the step configuration directory. -// -// 1. If the base step path has a current context configured, then this method -// returns the path to the authority configured in the context. -// 2. If the base step path does not have a current context configured this -// method returns the value defined by the environment variable STEPPATH, OR -// 3. If no environment variable is set, this method returns `$HOME/.step`. -func Path() string { - c := Contexts().GetCurrent() - if c == nil { - return BasePath() - } - return filepath.Join(BasePath(), "authorities", c.Authority) -} - -// ProfilePath returns the path for the currently selected profile path. -// -// 1. If the base step path has a current context configured, then this method -// returns the path to the profile configured in the context. -// 2. If the base step path does not have a current context configured this -// method returns the value defined by the environment variable STEPPATH, OR -// 3. If no environment variable is set, this method returns `$HOME/.step`. -func ProfilePath() string { - c := Contexts().GetCurrent() - if c == nil { - return BasePath() - } - return filepath.Join(BasePath(), "profiles", c.Profile) -} - -// IdentityPath returns the location of the identity directory. -func IdentityPath() string { - return filepath.Join(Path(), "identity") -} - -// IdentityFile returns the location of the identity file. -func IdentityFile() string { - return filepath.Join(Path(), "config", "identity.json") -} - -// DefaultsFile returns the location of the defaults file at the base of the -// authority path. -func DefaultsFile() string { - return filepath.Join(Path(), "config", "defaults.json") -} - -// ProfileDefaultsFile returns the location of the defaults file at the base -// of the profile path. -func ProfileDefaultsFile() string { - return filepath.Join(ProfilePath(), "config", "defaults.json") -} - -// ConfigPath returns the location of the $(step path)/config directory. -func ConfigPath() string { - return filepath.Join(Path(), "config") -} - -// ProfileConfigPath returns the location of the $(step path --profile)/config directory. -func ProfileConfigPath() string { - return filepath.Join(ProfilePath(), "config") -} - -// CaConfigFile returns the location of the ca.json file -- configuration for -// connecting to the CA. -func CaConfigFile() string { - return filepath.Join(Path(), "config", "ca.json") -} - -// ContextsFile returns the location of the config file. -func ContextsFile() string { - return filepath.Join(BasePath(), "contexts.json") -} - -// CurrentContextFile returns the path to the file containing the current context. -func CurrentContextFile() string { - return filepath.Join(BasePath(), "current-context.json") -} - -// Abs returns the given path relative to the STEPPATH if it's not an -// absolute path, relative to the home directory using the special string "~/", -// or relative to the working directory using "./" -// -// Relative paths like 'certs/root_ca.crt' will be converted to -// '$STEPPATH/certs/root_ca.crt', but paths like './certs/root_ca.crt' will be -// relative to the current directory. Home relative paths like -// ~/certs/root_ca.crt will be converted to '$HOME/certs/root_ca.crt'. And -// absolute paths like '/certs/root_ca.crt' will remain the same. -func Abs(path string) string { - if filepath.IsAbs(path) { - return path - } - // Windows accept both \ and / - slashed := filepath.ToSlash(path) - switch { - case strings.HasPrefix(slashed, "~/"): - return filepath.Join(Home(), path[2:]) - case strings.HasPrefix(slashed, "./"), strings.HasPrefix(slashed, "../"): - if abs, err := filepath.Abs(path); err == nil { - return abs - } - return path - default: - return filepath.Join(Path(), path) - } -} - -// Set updates the name, version, and build time -func Set(n, v, t string) { - name = n - version = v - buildTime = t -} - -// Version returns the current version of the binary -func Version() string { - out := version - if version == "N/A" { - out = "0000000-dev" - } - - return fmt.Sprintf("%s/%s (%s/%s)", - name, out, runtime.GOOS, runtime.GOARCH) -} - -// ReleaseDate returns the time of when the binary was built -func ReleaseDate() string { - out := buildTime - if buildTime == "N/A" { - out = time.Now().UTC().Format("2006-01-02 15:04 MST") - } - - return out -} diff --git a/vendor/github.com/smallstep/cli-utils/step/context.go b/vendor/github.com/smallstep/cli-utils/step/context.go deleted file mode 100644 index c4f7e4e..0000000 --- a/vendor/github.com/smallstep/cli-utils/step/context.go +++ /dev/null @@ -1,565 +0,0 @@ -package step - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "reflect" - "sort" - "strings" - - "github.com/pkg/errors" - "github.com/urfave/cli" - - "github.com/smallstep/cli-utils/errs" - "github.com/smallstep/cli-utils/ui" -) - -// IgnoreEnvVar is a value added to a flag EnvVar to avoid the use of -// environment variables or configuration files. -const IgnoreEnvVar = "STEP_IGNORE_ENV_VAR" - -// Context represents a Step Path configuration context. A context is the -// combination of a profile and an authority. -type Context struct { - Name string `json:"-"` - Profile string `json:"profile"` - Authority string `json:"authority"` - config map[string]interface{} -} - -// Validate validates a context and returns an error if invalid. -func (c *Context) Validate() error { - suffix := "; check your $STEPPATH/contexts.json file" - if c == nil { - return errors.Errorf("context cannot be nil%s", suffix) - } - if c.Authority == "" { - return errors.Errorf("context cannot have an empty authority value%s", suffix) - } - if c.Profile == "" { - return errors.Errorf("context cannot have an empty profile value%s", suffix) - } - return nil -} - -// Path return the base path relative to the context. -func (c *Context) Path() string { - return filepath.Join(BasePath(), "authorities", c.Authority) -} - -// ProfilePath return the profile base path relative to the context. -func (c *Context) ProfilePath() string { - return filepath.Join(BasePath(), "profiles", c.Profile) -} - -// DefaultsFile returns the location of the defaults file for the context. -func (c *Context) DefaultsFile() string { - return filepath.Join(c.Path(), "config", "defaults.json") -} - -// ProfileDefaultsFile returns the location of the defaults file at the base -// of the profile path. -func (c *Context) ProfileDefaultsFile() string { - return filepath.Join(c.ProfilePath(), "config", "defaults.json") -} - -// Load loads the configuration for the given context. -func (c *Context) Load() error { - c.config = map[string]interface{}{} - for _, f := range []string{c.DefaultsFile(), c.ProfileDefaultsFile()} { - b, err := os.ReadFile(f) - if os.IsNotExist(err) { - continue - } else if err != nil { - return errs.FileError(err, f) - } - - values := make(map[string]interface{}) - if err := json.Unmarshal(b, &values); err != nil { - return errors.Wrapf(err, "error parsing %s", f) - } - - for k, v := range values { - c.config[k] = v - } - } - - attributesBannedFromConfig := []string{ - "context", - "profile", - "authority", - } - for _, attr := range attributesBannedFromConfig { - if _, ok := c.config[attr]; ok { - ui.Printf("cannot set '%s' attribute in config files\n", attr) - delete(c.config, attr) - } - } - - return nil -} - -// ContextMap represents the map of available Contexts that is stored -// at the base of the Step Path. -type ContextMap map[string]*Context - -type storedCurrent struct { - Context string `json:"context"` -} - -// CtxState is the type that manages context state for the cli. -type CtxState struct { - current *Context - contexts ContextMap - config map[string]interface{} -} - -var ctxState = &CtxState{} - -// Init initializes the context map and current context state. -func (cs *CtxState) Init() error { - if err := cs.initMap(); err != nil { - return err - } - if err := cs.initCurrent(); err != nil { - return err - } - return cs.load() -} - -func (cs *CtxState) initMap() error { - contextsFile := ContextsFile() - b, err := os.ReadFile(contextsFile) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return errs.FileError(err, contextsFile) - } - cs.contexts = ContextMap{} - if err := json.Unmarshal(b, &cs.contexts); err != nil { - return errors.Wrap(err, "error unmarshaling context map") - } - for k, ctx := range cs.contexts { - if err := ctx.Validate(); err != nil { - return errors.Wrapf(err, "error in context '%s'", k) - } - ctx.Name = k - } - return nil -} - -func (cs *CtxState) initCurrent() error { - currentCtxFile := CurrentContextFile() - b, err := os.ReadFile(currentCtxFile) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return errs.FileError(err, currentCtxFile) - } - - var sc storedCurrent - if err := json.Unmarshal(b, &sc); err != nil { - return errors.Wrap(err, "error unmarshaling current context") - } - - return cs.SetCurrent(sc.Context) -} - -func (cs *CtxState) load() error { - if cs.Enabled() && cs.GetCurrent() != nil { - if err := cs.GetCurrent().Load(); err != nil { - return fmt.Errorf("failed loading current context configuration: %w", err) - } - - return nil - } - - if err := cs.LoadVintage(""); err != nil { - return fmt.Errorf("failed loading context configuration: %w", err) - } - - return nil -} - -// LoadVintage loads context configuration from the vintage (non-context) path. -func (cs *CtxState) LoadVintage(f string) error { - if f == "" { - f = DefaultsFile() - } - - b, err := os.ReadFile(f) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return errs.FileError(err, f) - } - - cs.config = make(map[string]interface{}) - if err := json.Unmarshal(b, &cs.config); err != nil { - return errors.Wrapf(err, "error parsing %s", f) - } - return nil -} - -// GetConfig returns the current context configuration. -func (cs *CtxState) GetConfig() (map[string]interface{}, error) { - if cs.Enabled() { - cur := cs.GetCurrent() - if cur == nil { - return nil, errors.New("cannot get context configuration; no current context set") - } - return cur.config, nil - } - return cs.config, nil -} - -// SetCurrent sets the current context or returns an error if a context -// with the given name does not exist. -func (cs *CtxState) SetCurrent(name string) error { - var ok bool - cs.current, ok = cs.contexts[name] - if !ok { - return errors.Errorf("could not load context '%s'", name) - } - if len(cs.current.config) == 0 { - if err := cs.current.Load(); err != nil { - return err - } - } - return nil -} - -type contextSelect struct { - Name string - Context *Context -} - -// PromptContext gets user input to select a context. -func (cs *CtxState) PromptContext() error { - var items []*contextSelect - for _, context := range cs.List() { - items = append(items, &contextSelect{ - Name: context.Name, - Context: context, - }) - } - - var ctxStr string - if len(items) == 1 { - if err := ui.PrintSelected("Context", items[0].Name); err != nil { - return err - } - ctxStr = items[0].Name - } else { - i, _, err := ui.Select("Select a context for 'step':", items, - ui.WithSelectTemplates(ui.NamedSelectTemplates("Context"))) - if err != nil { - return err - } - ctxStr = items[i].Name - } - if err := cs.SetCurrent(ctxStr); err != nil { - return err - } - return cs.SaveCurrent(ctxStr) -} - -// Enabled returns true if one of the following is true: -// - there is a current context configured -// - the context map is (list of available contexts) is not empty. -func (cs *CtxState) Enabled() bool { - return cs.current != nil || len(cs.contexts) > 0 -} - -// Contexts returns an object that enables context management. -func Contexts() *CtxState { - return ctxState -} - -// Add adds a new context to the context map. If current context is not -// set then store the new context as the current context for future commands. -func (cs *CtxState) Add(ctx *Context) error { - if err := ctx.Validate(); err != nil { - return errors.Wrapf(err, "error adding context") - } - if cs.contexts == nil { - cs.contexts = map[string]*Context{ctx.Name: ctx} - } else { - cs.contexts[ctx.Name] = ctx - } - - b, err := json.MarshalIndent(cs.contexts, "", " ") - if err != nil { - return err - } - - cf := ContextsFile() - if err := os.MkdirAll(filepath.Dir(cf), 0700); err != nil { - return errs.FileError(err, cf) - } - if err := os.WriteFile(cf, b, 0600); err != nil { - return errs.FileError(err, cf) - } - - if cs.current == nil { - if err := cs.SaveCurrent(ctx.Name); err != nil { - return err - } - } - return nil -} - -// GetCurrent returns the current context. -func (cs *CtxState) GetCurrent() *Context { - return cs.current -} - -// Get returns the context with the given name. -func (cs *CtxState) Get(name string) (ctx *Context, ok bool) { - ctx, ok = cs.contexts[name] - return -} - -// Remove removes a context from the context state. -func (cs *CtxState) Remove(name string) error { - if _, ok := cs.contexts[name]; !ok { - return errors.Errorf("context '%s' not found", name) - } - if cs.current != nil && cs.current.Name == name { - return errors.New("cannot remove current context; use 'step context select' to switch contexts") - } - - delete(cs.contexts, name) - - b, err := json.MarshalIndent(cs.contexts, "", " ") - if err != nil { - return err - } - - if err := os.WriteFile(ContextsFile(), b, 0600); err != nil { - return fmt.Errorf("error writing file: %w", err) - } - return nil -} - -// List returns a list of all contexts. -func (cs *CtxState) List() []*Context { - l := make([]*Context, 0, len(cs.contexts)) - - for _, v := range cs.contexts { - l = append(l, v) - } - return l -} - -// ListAlphabetical returns a case-insensitive, alphabetically -// sorted list of all contexts. -func (cs *CtxState) ListAlphabetical() []*Context { - l := cs.List() - - sort.Slice(l, func(i, j int) bool { - return strings.ToLower(l[i].Name) < strings.ToLower(l[j].Name) - }) - - return l -} - -// SaveCurrent stores the given context name as the selected default context for -// future commands. -func (cs *CtxState) SaveCurrent(name string) error { - if _, ok := Contexts().Get(name); !ok { - return errors.Errorf("context '%s' not found", name) - } - - b, err := json.Marshal(storedCurrent{Context: name}) - if err != nil { - return err - } - //nolint:gosec // this file does not contain sensitive info - if err = os.WriteFile(CurrentContextFile(), b, 0644); err != nil { - return errs.FileError(err, CurrentContextFile()) - } - return nil -} - -// Apply the current context configuration to the command line environment. -func (cs *CtxState) Apply(ctx *cli.Context) error { - cfg, err := cs.GetConfig() - if err != nil { - return err - } - for _, f := range ctx.Command.Flags { - // Skip if EnvVar == IgnoreEnvVar - if getFlagEnvVar(f) == IgnoreEnvVar { - continue - } - - for _, name := range strings.Split(f.GetName(), ",") { - name = strings.TrimSpace(name) - if ctx.IsSet(name) { - break - } - // Set the flag for the first key that matches. - if v, ok := cfg[name]; ok { - ctx.Set(name, fmt.Sprintf("%v", v)) - break - } - } - } - return nil -} - -// getEnvVar generates the environment variable for the given flag name. -func getEnvVar(name string) string { - parts := strings.Split(name, ",") - name = strings.TrimSpace(parts[0]) - name = strings.ReplaceAll(name, "-", "_") - return "STEP_" + strings.ToUpper(name) -} - -// getFlagEnvVar returns the value of the EnvVar field of a flag. -func getFlagEnvVar(f cli.Flag) string { - v := reflect.ValueOf(f) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() == reflect.Struct { - envVar := v.FieldByName("EnvVar") - if envVar.IsValid() { - return envVar.String() - } - } - return "" -} - -// SetEnvVar sets the the EnvVar element to each flag recursively. -func SetEnvVar(c *cli.Command) { - if c == nil { - return - } - - // Enable getting the flags from a json file - if c.Before == nil && c.Action != nil { - c.Before = getConfigVars - } - - // Enable getting the flags from environment variables - for i := range c.Flags { - envVar := getEnvVar(c.Flags[i].GetName()) - switch f := c.Flags[i].(type) { - case cli.BoolFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.BoolTFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.DurationFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Float64Flag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.GenericFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Int64Flag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.IntFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.IntSliceFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Int64SliceFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.StringFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.StringSliceFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.Uint64Flag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - case cli.UintFlag: - if f.EnvVar == "" { - f.EnvVar = envVar - c.Flags[i] = f - } - } - } - - for i := range c.Subcommands { - SetEnvVar(&c.Subcommands[i]) - } -} - -// GetConfigVars load the defaults.json file and sets the flags if they are not -// already set or the EnvVar is set to IgnoreEnvVar. -// -// TODO(mariano): right now it only supports parameters at first level. -func getConfigVars(ctx *cli.Context) (err error) { - if ctx.Bool("no-context") { - return nil - } - - cs := Contexts() - - // Load the the current context into memory: - // - If contexts enabled then make sure a current context is selected - // and loaded. - // - If vintage context then check if overwritten by --config flag. - if cs.Enabled() { - if ctx.IsSet("context") { - err = cs.SetCurrent(ctx.String("context")) - } else if cs.Enabled() && cs.GetCurrent() == nil { - err = cs.PromptContext() - } - if err != nil { - return err - } - } else if ctx.GlobalString("config") != "" { - // Re-load the vintage context configuration if `--config` flag supplied. - cs.LoadVintage(ctx.GlobalString("config")) - } - - // TODO: a mock detail because of "add detail/assignee to this TODO/FIXME/BUG comment" lint issue - fullCommandName := strings.ToLower(strings.TrimSpace(ctx.Command.FullName())) - if strings.EqualFold(fullCommandName, "ca bootstrap-helper") { - return nil - } - - if err := cs.Apply(ctx); err != nil { - return fmt.Errorf("error applying contexts: %w", err) - } - - return nil -} diff --git a/vendor/github.com/smallstep/cli-utils/ui/options.go b/vendor/github.com/smallstep/cli-utils/ui/options.go deleted file mode 100644 index 382c263..0000000 --- a/vendor/github.com/smallstep/cli-utils/ui/options.go +++ /dev/null @@ -1,172 +0,0 @@ -package ui - -import ( - "fmt" - "regexp" - "strings" - - "github.com/manifoldco/promptui" -) - -type options struct { - mask rune - defaultValue string - value string - allowEdit bool - printTemplate string - promptTemplates *promptui.PromptTemplates - selectTemplates *promptui.SelectTemplates - validateFunc promptui.ValidateFunc -} - -// apply applies the given options. -func (o *options) apply(opts []Option) *options { - for _, fn := range opts { - fn(o) - } - return o -} - -// valid returns true if the validate function passes on the value. -func (o *options) valid() bool { - if o.validateFunc == nil { - return true - } - return o.validateFunc(o.value) == nil -} - -// getValue validates the value and returns it. -func (o *options) getValue() (string, error) { - if o.validateFunc == nil { - return o.value, nil - } - if err := o.validateFunc(o.value); err != nil { - return "", err - } - return o.value, nil -} - -// getValueBytes validates the value and returns it as a byte slice. -func (o *options) getValueBytes() ([]byte, error) { - if o.validateFunc == nil { - return []byte(o.value), nil - } - if err := o.validateFunc(o.value); err != nil { - return nil, err - } - return []byte(o.value), nil -} - -// Option is the type of the functions that modify the prompt options. -type Option func(*options) - -func extractOptions(args []interface{}) (opts []Option, rest []interface{}) { - rest = args[:0] - for _, arg := range args { - if o, ok := arg.(Option); ok { - opts = append(opts, o) - } else { - rest = append(rest, arg) - } - } - return -} - -// WithMask adds a mask to a prompt. -func WithMask(r rune) Option { - return func(o *options) { - o.mask = r - } -} - -// WithDefaultValue adds a custom string as the default value. -func WithDefaultValue(s string) Option { - return func(o *options) { - o.defaultValue = s - } -} - -// WithSliceValue sets a custom string as the result of a prompt. If value is set, -// the prompt won't be displayed. -func WithSliceValue(values []string) Option { - return func(o *options) { - o.value = strings.Join(values, ",") - } -} - -// WithValue sets a custom string as the result of a prompt. If value is set, -// the prompt won't be displayed. -func WithValue(value string) Option { - return func(o *options) { - o.value = value - } -} - -// WithAllowEdit if true, let's the user edit the default value set. -func WithAllowEdit(b bool) Option { - return func(o *options) { - o.allowEdit = b - } -} - -// WithPrintTemplate sets the template to use on the print methods. -func WithPrintTemplate(template string) Option { - return func(o *options) { - o.printTemplate = template - } -} - -// WithPromptTemplates adds a custom template to a prompt. -func WithPromptTemplates(t *promptui.PromptTemplates) Option { - return func(o *options) { - o.promptTemplates = t - } -} - -// WithSelectTemplates adds a custom template to a select. -func WithSelectTemplates(t *promptui.SelectTemplates) Option { - return func(o *options) { - o.selectTemplates = t - } -} - -// WithValidateFunc adds a custom validation function to a prompt. -func WithValidateFunc(fn func(string) error) Option { - return func(o *options) { - o.validateFunc = fn - } -} - -// WithValidateNotEmpty adds a custom validation function to a prompt that -// checks that the propted string is not empty. -func WithValidateNotEmpty() Option { - return WithValidateFunc(NotEmpty()) -} - -// WithValidateYesNo adds a custom validation function to a prompt for a Yes/No -// prompt. -func WithValidateYesNo() Option { - return WithValidateFunc(YesNo()) -} - -// WithRichPrompt add the template option with rich templates. -func WithRichPrompt() Option { - return WithPromptTemplates(PromptTemplates()) -} - -// WithSimplePrompt add the template option with simple templates. -func WithSimplePrompt() Option { - return WithPromptTemplates(SimplePromptTemplates()) -} - -// WithValidateRegexp checks a prompt answer with a regular expression. If the -// regular expression is not a valid one, the option will panic. -func WithValidateRegexp(re string) Option { - rx := regexp.MustCompile(re) - return WithValidateFunc(func(s string) error { - if rx.MatchString(s) { - return nil - } - return fmt.Errorf("%s does not match the regular expresion %s", s, re) - }) -} diff --git a/vendor/github.com/smallstep/cli-utils/ui/templates.go b/vendor/github.com/smallstep/cli-utils/ui/templates.go deleted file mode 100644 index cc37891..0000000 --- a/vendor/github.com/smallstep/cli-utils/ui/templates.go +++ /dev/null @@ -1,93 +0,0 @@ -package ui - -import ( - "fmt" - "runtime" - - "github.com/chzyer/readline" - "github.com/manifoldco/promptui" -) - -var ( - // IconInitial is the icon used when starting in prompt mode and the icon next to the label when - // starting in select mode. - IconInitial = promptui.Styler(promptui.FGBlue)("?") - - // IconGood is the icon used when a good answer is entered in prompt mode. - IconGood = promptui.Styler(promptui.FGGreen)("✔") - - // IconWarn is the icon used when a good, but potentially invalid answer is entered in prompt mode. - IconWarn = promptui.Styler(promptui.FGYellow)("⚠") - - // IconBad is the icon used when a bad answer is entered in prompt mode. - IconBad = promptui.Styler(promptui.FGRed)("✗") - - // IconSelect is the icon used to identify the currently selected item in select mode. - IconSelect = promptui.Styler(promptui.FGBold)("▸") -) - -func init() { - // Set VT100 characters for windows too - if runtime.GOOS == "windows" { - promptui.KeyEnter = readline.CharEnter - promptui.KeyBackspace = readline.CharBackspace - promptui.KeyPrev = readline.CharPrev - promptui.KeyPrevDisplay = "↑" - promptui.KeyNext = readline.CharNext - promptui.KeyNextDisplay = "↓" - promptui.KeyBackward = readline.CharBackward - promptui.KeyBackwardDisplay = "←" - promptui.KeyForward = readline.CharForward - promptui.KeyForwardDisplay = "→" - } -} - -// PrintSelectedTemplate returns the default template used in PrintSelected. -func PrintSelectedTemplate() string { - return fmt.Sprintf(`{{ %q | green }} {{ .Name | bold }}{{ ":" | bold }} {{ .Value }}`, IconGood) + "\n" -} - -// PromptTemplates is the default style for a prompt. -func PromptTemplates() *promptui.PromptTemplates { - bold := promptui.Styler(promptui.FGBold) - return &promptui.PromptTemplates{ - Prompt: fmt.Sprintf("%s {{ . | bold }}%s ", IconInitial, bold(":")), - Success: fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":")), - // Confirm: fmt.Sprintf(`{{ "%s" | bold }} {{ . | bold }}? {{ "[]" | faint }} `, IconInitial), - Valid: fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconGood), bold(":")), - Invalid: fmt.Sprintf("%s {{ . | bold }}%s ", bold(IconBad), bold(":")), - } -} - -// SimplePromptTemplates is a prompt with a simple style, used by default on password prompts. -func SimplePromptTemplates() *promptui.PromptTemplates { - return &promptui.PromptTemplates{ - Prompt: "{{ . }}: ", - Success: "{{ . }}: ", - Valid: "{{ . }}: ", - Invalid: "{{ . }}: ", - } -} - -// SelectTemplates returns the default promptui.SelectTemplate for string -// slices. The given name is the prompt of the selected option. -func SelectTemplates(name string) *promptui.SelectTemplates { - return &promptui.SelectTemplates{ - Label: fmt.Sprintf("%s {{ . }}: ", IconInitial), - Active: fmt.Sprintf("%s {{ . | underline }}", IconSelect), - Inactive: " {{ . }}", - Selected: fmt.Sprintf(`{{ %q | green }} {{ "%s:" | bold }} {{ .Name }}`, IconGood, name), - } -} - -// NamedSelectTemplates returns the default promptui.SelectTemplate for struct -// slices with a name property. The given name is the prompt of the selected -// option. -func NamedSelectTemplates(name string) *promptui.SelectTemplates { - return &promptui.SelectTemplates{ - Label: fmt.Sprintf("%s {{.Name}}: ", IconInitial), - Active: fmt.Sprintf("%s {{ .Name | underline }}", IconSelect), - Inactive: " {{.Name}}", - Selected: fmt.Sprintf(`{{ %q | green }} {{ "%s:" | bold }} {{ .Name }}`, IconGood, name), - } -} diff --git a/vendor/github.com/smallstep/cli-utils/ui/ui.go b/vendor/github.com/smallstep/cli-utils/ui/ui.go deleted file mode 100644 index 40fbc0d..0000000 --- a/vendor/github.com/smallstep/cli-utils/ui/ui.go +++ /dev/null @@ -1,334 +0,0 @@ -package ui - -import ( - "fmt" - "os" - "strings" - "text/template" - - "github.com/chzyer/readline" - "github.com/manifoldco/promptui" - "github.com/pkg/errors" - "go.step.sm/crypto/randutil" -) - -// stderr implements an io.WriteCloser that skips the terminal bell character -// (ASCII code 7), and writes the rest to os.Stderr. It's used to replace -// readline.Stdout, that is the package used by promptui to display the prompts. -type stderr struct{} - -// Write implements an io.WriterCloser over os.Stderr, but it skips the terminal -// bell character. -func (s *stderr) Write(b []byte) (int, error) { - if len(b) == 1 && b[0] == readline.CharBell { - return 0, nil - } - return os.Stderr.Write(b) -} - -// Close implements an io.WriterCloser over os.Stderr. -func (s *stderr) Close() error { - return os.Stderr.Close() -} - -func init() { - readline.Stdout = &stderr{} -} - -// Init initializes the terminal to be used by this package. This is generally a -// noop except for windows. -func Init() { - setConsoleMode() -} - -// Reset sets the terminal as it was before the initialization. This is -// generally a noop except for windows. -func Reset() { - resetConsoleMode() -} - -// Print uses templates to print the arguments formated to os.Stderr. -func Print(args ...interface{}) error { - var o options - opts, args := extractOptions(args) - o.apply(opts) - - // Return with a default value. This is useful when we split the question - // and the response in two lines. - if o.value != "" && o.valid() { - return nil - } - - text := fmt.Sprint(args...) - t, err := template.New("Print").Funcs(promptui.FuncMap).Parse(text) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - if err := t.Execute(os.Stderr, nil); err != nil { - return errors.Wrap(err, "error executing template") - } - return nil -} - -// Printf uses templates to print the string formated to os.Stderr. -func Printf(format string, args ...interface{}) error { - var o options - opts, args := extractOptions(args) - o.apply(opts) - - // Return with a default value. This is useful when we split the question - // and the response in two lines. - if o.value != "" && o.valid() { - return nil - } - - text := fmt.Sprintf(format, args...) - t, err := template.New("Printf").Funcs(promptui.FuncMap).Parse(text) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - if err := t.Execute(os.Stderr, nil); err != nil { - return errors.Wrap(err, "error executing template") - } - return nil -} - -// Println uses templates to print the given arguments to os.Stderr -func Println(args ...interface{}) error { - var o options - opts, args := extractOptions(args) - o.apply(opts) - - // Return with a default value. This is useful when we split the question - // and the response in two lines. - if o.value != "" && o.valid() { - return nil - } - - text := fmt.Sprintln(args...) - t, err := template.New("Println").Funcs(promptui.FuncMap).Parse(text) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - if err := t.Execute(os.Stderr, nil); err != nil { - return errors.Wrap(err, "error executing template") - } - return nil -} - -// PrintSelected prints the given name and value as if they were selected from a -// promptui.Select. -func PrintSelected(name, value string, opts ...Option) error { - o := &options{ - printTemplate: PrintSelectedTemplate(), - } - o.apply(opts) - - t, err := template.New(name).Funcs(promptui.FuncMap).Parse(o.printTemplate) - if err != nil { - return errors.Wrap(err, "error parsing template") - } - - data := struct { - Name string - Value string - }{name, value} - if err := t.Execute(os.Stderr, data); err != nil { - return errors.Wrap(err, "error executing template") - } - - return nil -} - -// Prompt creates and runs a promptui.Prompt with the given label. -func Prompt(label string, opts ...Option) (string, error) { - o := &options{ - promptTemplates: PromptTemplates(), - } - o.apply(opts) - - // Return value if set - if o.value != "" { - return o.getValue() - } - - // Prompt using the terminal - clean, err := preparePromptTerminal() - if err != nil { - return "", err - } - defer clean() - - prompt := &promptui.Prompt{ - Label: label, - Default: o.defaultValue, - AllowEdit: o.allowEdit, - Validate: o.validateFunc, - Templates: o.promptTemplates, - } - value, err := prompt.Run() - if err != nil { - return "", errors.Wrap(err, "error running prompt") - } - return value, nil -} - -// PromptPassword creates and runs a promptui.Prompt with the given label. This -// prompt will mask the key entries with \r. -func PromptPassword(label string, opts ...Option) ([]byte, error) { - // Using a not printable character as they work better than \r - o := &options{ - mask: 1, - promptTemplates: SimplePromptTemplates(), - } - o.apply(opts) - - // Return value if set - if o.value != "" { - return o.getValueBytes() - } - - // Prompt using the terminal - clean, err := preparePromptTerminal() - if err != nil { - return nil, err - } - defer clean() - - prompt := &promptui.Prompt{ - Label: label, - Mask: o.mask, - Default: o.defaultValue, - AllowEdit: o.allowEdit, - Validate: o.validateFunc, - Templates: o.promptTemplates, - } - pass, err := prompt.Run() - if err != nil { - return nil, errors.Wrap(err, "error reading password") - } - return []byte(pass), nil -} - -// PromptPasswordGenerate creates and runs a promptui.Prompt with the given label. -// This prompt will mask the key entries with \r. If the result password length -// is 0, it will generate a new prompt with a generated password that can be -// edited. -func PromptPasswordGenerate(label string, opts ...Option) ([]byte, error) { - pass, err := PromptPassword(label, opts...) - if err != nil || len(pass) > 0 { - return pass, err - } - passString, err := randutil.Alphanumeric(32) - if err != nil { - return nil, err - } - passString, err = Prompt("Password", WithDefaultValue(passString), WithAllowEdit(true), WithValidateNotEmpty()) - if err != nil { - return nil, err - } - return []byte(passString), nil -} - -// PromptYesNo creates and runs a promptui.Prompt with the given label, and -// returns true if the answer is y/yes and false if the answer is n/no. -func PromptYesNo(label string, opts ...Option) (bool, error) { - opts = append([]Option{WithValidateYesNo()}, opts...) - s, err := Prompt(label, opts...) - if err != nil { - return false, err - } - switch strings.ToLower(strings.TrimSpace(s)) { - case "y", "yes": - return true, nil - case "n", "no": - return false, nil - default: - return false, fmt.Errorf("%s is not a valid answer", s) - } -} - -// Select creates and runs a promptui.Select with the given label and items. -func Select(label string, items interface{}, opts ...Option) (int, string, error) { - o := &options{ - selectTemplates: SelectTemplates(label), - } - o.apply(opts) - - clean, err := prepareSelectTerminal() - if err != nil { - return 0, "", err - } - defer clean() - - prompt := &promptui.Select{ - Label: label, - Items: items, - Templates: o.selectTemplates, - } - n, s, err := prompt.Run() - if err != nil { - return 0, "", errors.Wrap(err, "error running prompt") - } - return n, s, nil -} - -func preparePromptTerminal() (func(), error) { - nothing := func() {} - if !readline.DefaultIsTerminal() { - tty, err := os.Open("/dev/tty") - if err != nil { - return nothing, errors.Wrap(err, "error allocating terminal") - } - clean := func() { - tty.Close() - } - - fd := int(tty.Fd()) - state, err := readline.MakeRaw(fd) - if err != nil { - defer clean() - return nothing, errors.Wrap(err, "error making raw terminal") - } - stdin := readline.Stdin - readline.Stdin = tty - clean = func() { - readline.Stdin = stdin - readline.Restore(fd, state) - tty.Close() - } - return clean, nil - } - - return nothing, nil -} - -func prepareSelectTerminal() (func(), error) { - nothing := func() {} - if !readline.DefaultIsTerminal() { - tty, err := os.Open("/dev/tty") - if err != nil { - return nothing, errors.Wrap(err, "error allocating terminal") - } - clean := func() { - tty.Close() - } - - fd := int(tty.Fd()) - state, err := readline.MakeRaw(fd) - if err != nil { - defer clean() - return nothing, errors.Wrap(err, "error making raw terminal") - } - stdin := os.Stdin - os.Stdin = tty - clean = func() { - os.Stdin = stdin - readline.Restore(fd, state) - tty.Close() - } - return clean, nil - } - - return nothing, nil -} diff --git a/vendor/github.com/smallstep/cli-utils/ui/ui_other.go b/vendor/github.com/smallstep/cli-utils/ui/ui_other.go deleted file mode 100644 index f449b57..0000000 --- a/vendor/github.com/smallstep/cli-utils/ui/ui_other.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !windows -// +build !windows - -package ui - -func setConsoleMode() {} - -func resetConsoleMode() {} diff --git a/vendor/github.com/smallstep/cli-utils/ui/ui_windows.go b/vendor/github.com/smallstep/cli-utils/ui/ui_windows.go deleted file mode 100644 index 573bfcb..0000000 --- a/vendor/github.com/smallstep/cli-utils/ui/ui_windows.go +++ /dev/null @@ -1,51 +0,0 @@ -//go:build windows -// +build windows - -package ui - -import ( - "fmt" - "os" - - "golang.org/x/sys/windows" -) - -var inMode, outMode uint32 - -func init() { - var _ = windows.GetConsoleMode(windows.Stdin, &inMode) - var _ = windows.GetConsoleMode(windows.Stdout, &outMode) -} - -func setConsoleMode() { - in := inMode | windows.ENABLE_VIRTUAL_TERMINAL_INPUT - out := outMode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - - if inMode != 0 && inMode != in { - if err := windows.SetConsoleMode(windows.Stdin, in); err != nil { - fmt.Fprintf(os.Stderr, "Failed to set console mode: %v\n", err) - } - } - - if outMode != 0 && outMode != out { - if err := windows.SetConsoleMode(windows.Stdout, out); err != nil { - fmt.Fprintf(os.Stderr, "Failed to set console mode: %v\n", err) - } - } -} - -func resetConsoleMode() { - in := inMode | windows.ENABLE_VIRTUAL_TERMINAL_INPUT - out := outMode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING - - if inMode != 0 && inMode != in { - if err := windows.SetConsoleMode(windows.Stdin, inMode); err != nil { - fmt.Fprintf(os.Stderr, "Failed to reset console mode: %v\n", err) - } - } - if outMode != 0 && outMode != out { - if err := windows.SetConsoleMode(windows.Stdout, outMode); err != nil { - fmt.Fprintf(os.Stderr, "Failed to reset console mode: %v\n", err) - } - } -} diff --git a/vendor/github.com/smallstep/cli-utils/ui/validators.go b/vendor/github.com/smallstep/cli-utils/ui/validators.go deleted file mode 100644 index 7d8b603..0000000 --- a/vendor/github.com/smallstep/cli-utils/ui/validators.go +++ /dev/null @@ -1,75 +0,0 @@ -package ui - -import ( - "errors" - "fmt" - "net" - "strings" - - "github.com/manifoldco/promptui" -) - -var errEmptyValue = errors.New("value is empty") - -// NotEmpty is a validation function that checks that the prompted string is not -// empty. -func NotEmpty() promptui.ValidateFunc { - return func(s string) error { - if strings.TrimSpace(s) == "" { - return errEmptyValue - } - return nil - } -} - -// Address is a validation function that checks that the prompted string is a -// valid TCP address. -func Address() promptui.ValidateFunc { - return func(s string) error { - if _, _, err := net.SplitHostPort(s); err != nil { - return fmt.Errorf("%s is not an TCP address", s) - } - return nil - } -} - -// IPAddress is validation function that checks that the prompted string is a -// valid IP address. -func IPAddress() promptui.ValidateFunc { - return func(s string) error { - if net.ParseIP(s) == nil { - return fmt.Errorf("%s is not an ip address", s) - } - return nil - } -} - -// DNS is a validation function that checks that the prompted string is a valid -// DNS name or IP address. -func DNS() promptui.ValidateFunc { - return func(s string) error { - if strings.TrimSpace(s) == "" { - return errEmptyValue - } - if ip := net.ParseIP(s); ip != nil { - return nil - } - if _, _, err := net.SplitHostPort(s + ":443"); err != nil { - return fmt.Errorf("%s is not a valid DNS name or IP address", s) - } - return nil - } -} - -// YesNo is a validation function that checks for a Yes/No answer. -func YesNo() promptui.ValidateFunc { - return func(s string) error { - s = strings.ToLower(strings.TrimSpace(s)) - switch s { - case "y", "yes", "n", "no": - return nil - default: - return fmt.Errorf("%s is not a valid answer", s) - } - } -} diff --git a/vendor/github.com/smallstep/cli-utils/usage/css.go b/vendor/github.com/smallstep/cli-utils/usage/css.go deleted file mode 100644 index e552534..0000000 --- a/vendor/github.com/smallstep/cli-utils/usage/css.go +++ /dev/null @@ -1,764 +0,0 @@ -package usage - -// CSS code replicating Github style. -// From https://github.com/sindresorhus/github-markdown-css -// MIT license -var css = `@font-face { - font-family: octicons-link; - src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff'); -} - -.wrapper { - margin: 0 auto; - max-width: 700px; - padding: 20px 10px; -} - -.markdown-body { - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - line-height: 1.5; - color: #24292e; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - font-size: 16px; - line-height: 1.5; - word-wrap: break-word; -} - -.markdown-body .pl-c { - color: #6a737d; -} - -.markdown-body .pl-c1, -.markdown-body .pl-s .pl-v { - color: #005cc5; -} - -.markdown-body .pl-e, -.markdown-body .pl-en { - color: #6f42c1; -} - -.markdown-body .pl-smi, -.markdown-body .pl-s .pl-s1 { - color: #24292e; -} - -.markdown-body .pl-ent { - color: #22863a; -} - -.markdown-body .pl-k { - color: #d73a49; -} - -.markdown-body .pl-s, -.markdown-body .pl-pds, -.markdown-body .pl-s .pl-pse .pl-s1, -.markdown-body .pl-sr, -.markdown-body .pl-sr .pl-cce, -.markdown-body .pl-sr .pl-sre, -.markdown-body .pl-sr .pl-sra { - color: #032f62; -} - -.markdown-body .pl-v, -.markdown-body .pl-smw { - color: #e36209; -} - -.markdown-body .pl-bu { - color: #b31d28; -} - -.markdown-body .pl-ii { - color: #fafbfc; - background-color: #b31d28; -} - -.markdown-body .pl-c2 { - color: #fafbfc; - background-color: #d73a49; -} - -.markdown-body .pl-c2::before { - content: "^M"; -} - -.markdown-body .pl-sr .pl-cce { - font-weight: bold; - color: #22863a; -} - -.markdown-body .pl-ml { - color: #735c0f; -} - -.markdown-body .pl-mh, -.markdown-body .pl-mh .pl-en, -.markdown-body .pl-ms { - font-weight: bold; - color: #005cc5; -} - -.markdown-body .pl-mi { - font-style: italic; - color: #24292e; -} - -.markdown-body .pl-mb { - font-weight: bold; - color: #24292e; -} - -.markdown-body .pl-md { - color: #b31d28; - background-color: #ffeef0; -} - -.markdown-body .pl-mi1 { - color: #22863a; - background-color: #f0fff4; -} - -.markdown-body .pl-mc { - color: #e36209; - background-color: #ffebda; -} - -.markdown-body .pl-mi2 { - color: #f6f8fa; - background-color: #005cc5; -} - -.markdown-body .pl-mdr { - font-weight: bold; - color: #6f42c1; -} - -.markdown-body .pl-ba { - color: #586069; -} - -.markdown-body .pl-sg { - color: #959da5; -} - -.markdown-body .pl-corl { - text-decoration: underline; - color: #032f62; -} - -.markdown-body .octicon { - display: inline-block; - vertical-align: text-top; - fill: currentColor; -} - -.markdown-body a { - background-color: transparent; -} - -.markdown-body a:active, -.markdown-body a:hover { - outline-width: 0; -} - -.markdown-body strong { - font-weight: inherit; -} - -.markdown-body strong { - font-weight: bolder; -} - -.markdown-body h1 { - font-size: 2em; - margin: 0.67em 0; -} - -.markdown-body img { - border-style: none; -} - -.markdown-body code, -.markdown-body kbd, -.markdown-body pre { - font-family: monospace, monospace; - font-size: 1em; -} - -.markdown-body hr { - box-sizing: content-box; - height: 0; - overflow: visible; -} - -.markdown-body input { - font: inherit; - margin: 0; -} - -.markdown-body input { - overflow: visible; -} - -.markdown-body [type="checkbox"] { - box-sizing: border-box; - padding: 0; -} - -.markdown-body * { - box-sizing: border-box; -} - -.markdown-body input { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} - -.markdown-body a { - color: #0366d6; - text-decoration: none; -} - -.markdown-body a:hover { - text-decoration: underline; -} - -.markdown-body strong { - font-weight: 600; -} - -.markdown-body hr { - height: 0; - margin: 15px 0; - overflow: hidden; - background: transparent; - border: 0; - border-bottom: 1px solid #dfe2e5; -} - -.markdown-body hr::before { - display: table; - content: ""; -} - -.markdown-body hr::after { - display: table; - clear: both; - content: ""; -} - -.markdown-body table { - border-spacing: 0; - border-collapse: collapse; -} - -.markdown-body td, -.markdown-body th { - padding: 0; -} - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3, -.markdown-body h4, -.markdown-body h5, -.markdown-body h6 { - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body h1 { - font-size: 32px; - font-weight: 600; -} - -.markdown-body h2 { - font-size: 24px; - font-weight: 600; -} - -.markdown-body h3 { - font-size: 20px; - font-weight: 600; -} - -.markdown-body h4 { - font-size: 16px; - font-weight: 600; -} - -.markdown-body h5 { - font-size: 14px; - font-weight: 600; -} - -.markdown-body h6 { - font-size: 12px; - font-weight: 600; -} - -.markdown-body p { - margin-top: 0; - margin-bottom: 10px; -} - -.markdown-body blockquote { - margin: 0; -} - -.markdown-body ul, -.markdown-body ol { - padding-left: 0; - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body ol ol, -.markdown-body ul ol { - list-style-type: lower-roman; -} - -.markdown-body ul ul ol, -.markdown-body ul ol ol, -.markdown-body ol ul ol, -.markdown-body ol ol ol { - list-style-type: lower-alpha; -} - -.markdown-body dd { - margin-left: 0; -} - -.markdown-body code { - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 12px; -} - -.markdown-body pre { - margin-top: 0; - margin-bottom: 0; - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 12px; -} - -.markdown-body .octicon { - vertical-align: text-bottom; -} - -.markdown-body .pl-0 { - padding-left: 0 !important; -} - -.markdown-body .pl-1 { - padding-left: 4px !important; -} - -.markdown-body .pl-2 { - padding-left: 8px !important; -} - -.markdown-body .pl-3 { - padding-left: 16px !important; -} - -.markdown-body .pl-4 { - padding-left: 24px !important; -} - -.markdown-body .pl-5 { - padding-left: 32px !important; -} - -.markdown-body .pl-6 { - padding-left: 40px !important; -} - -.markdown-body::before { - display: table; - content: ""; -} - -.markdown-body::after { - display: table; - clear: both; - content: ""; -} - -.markdown-body>*:first-child { - margin-top: 0 !important; -} - -.markdown-body>*:last-child { - margin-bottom: 0 !important; -} - -.markdown-body a:not([href]) { - color: inherit; - text-decoration: none; -} - -.markdown-body .anchor { - float: left; - padding-right: 4px; - margin-left: -20px; - line-height: 1; -} - -.markdown-body .anchor:focus { - outline: none; -} - -.markdown-body p, -.markdown-body blockquote, -.markdown-body ul, -.markdown-body ol, -.markdown-body dl, -.markdown-body table, -.markdown-body pre { - margin-top: 0; - margin-bottom: 16px; -} - -.markdown-body hr { - height: 0.25em; - padding: 0; - margin: 24px 0; - background-color: #e1e4e8; - border: 0; -} - -.markdown-body blockquote { - padding: 0 1em; - color: #6a737d; - border-left: 0.25em solid #dfe2e5; -} - -.markdown-body blockquote>:first-child { - margin-top: 0; -} - -.markdown-body blockquote>:last-child { - margin-bottom: 0; -} - -.markdown-body kbd { - display: inline-block; - padding: 3px 5px; - font-size: 11px; - line-height: 10px; - color: #444d56; - vertical-align: middle; - background-color: #fafbfc; - border: solid 1px #c6cbd1; - border-bottom-color: #959da5; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #959da5; -} - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3, -.markdown-body h4, -.markdown-body h5, -.markdown-body h6 { - margin-top: 24px; - margin-bottom: 16px; - font-weight: 600; - line-height: 1.25; -} - -.markdown-body h1 .octicon-link, -.markdown-body h2 .octicon-link, -.markdown-body h3 .octicon-link, -.markdown-body h4 .octicon-link, -.markdown-body h5 .octicon-link, -.markdown-body h6 .octicon-link { - color: #1b1f23; - vertical-align: middle; - visibility: hidden; -} - -.markdown-body h1:hover .anchor, -.markdown-body h2:hover .anchor, -.markdown-body h3:hover .anchor, -.markdown-body h4:hover .anchor, -.markdown-body h5:hover .anchor, -.markdown-body h6:hover .anchor { - text-decoration: none; -} - -.markdown-body h1:hover .anchor .octicon-link, -.markdown-body h2:hover .anchor .octicon-link, -.markdown-body h3:hover .anchor .octicon-link, -.markdown-body h4:hover .anchor .octicon-link, -.markdown-body h5:hover .anchor .octicon-link, -.markdown-body h6:hover .anchor .octicon-link { - visibility: visible; -} - -.markdown-body h1 { - padding-bottom: 0.3em; - font-size: 2em; - border-bottom: 1px solid #eaecef; -} - -.markdown-body h2 { - padding-bottom: 0.3em; - font-size: 1.5em; - border-bottom: 1px solid #eaecef; -} - -.markdown-body h3 { - font-size: 1.25em; -} - -.markdown-body h4 { - font-size: 1em; -} - -.markdown-body h5 { - font-size: 0.875em; -} - -.markdown-body h6 { - font-size: 0.85em; - color: #6a737d; -} - -.markdown-body ul, -.markdown-body ol { - padding-left: 2em; -} - -.markdown-body ul ul, -.markdown-body ul ol, -.markdown-body ol ol, -.markdown-body ol ul { - margin-top: 0; - margin-bottom: 0; -} - -.markdown-body li { - word-wrap: break-all; -} - -.markdown-body li>p { - margin-top: 16px; -} - -.markdown-body li+li { - margin-top: 0.25em; -} - -.markdown-body dl { - padding: 0; -} - -.markdown-body dl dt { - padding: 0; - margin-top: 16px; - font-size: 1em; - font-style: italic; - font-weight: 600; -} - -.markdown-body dl dd { - padding: 0 16px; - margin-bottom: 16px; -} - -.markdown-body table { - display: block; - width: 100%; - overflow: auto; -} - -.markdown-body table th { - font-weight: 600; -} - -.markdown-body table th, -.markdown-body table td { - padding: 6px 13px; - border: 1px solid #dfe2e5; -} - -.markdown-body table tr { - background-color: #fff; - border-top: 1px solid #c6cbd1; -} - -.markdown-body table tr:nth-child(2n) { - background-color: #f6f8fa; -} - -.markdown-body img { - max-width: 100%; - box-sizing: content-box; - background-color: #fff; -} - -.markdown-body img[align=right] { - padding-left: 20px; -} - -.markdown-body img[align=left] { - padding-right: 20px; -} - -.markdown-body code { - padding: 0.2em 0.4em; - margin: 0; - font-size: 85%; - background-color: rgba(27,31,35,0.05); - border-radius: 3px; -} - -.markdown-body pre { - word-wrap: normal; -} - -.markdown-body pre>code { - padding: 0; - margin: 0; - font-size: 100%; - word-break: normal; - white-space: pre; - background: transparent; - border: 0; -} - -.markdown-body .highlight { - margin-bottom: 16px; -} - -.markdown-body .highlight pre { - margin-bottom: 0; - word-break: normal; -} - -.markdown-body .highlight pre, -.markdown-body pre { - padding: 16px; - overflow: auto; - font-size: 85%; - line-height: 1.45; - background-color: #f6f8fa; - border-radius: 3px; -} - -.markdown-body pre code { - display: inline; - max-width: auto; - padding: 0; - margin: 0; - overflow: visible; - line-height: inherit; - word-wrap: normal; - background-color: transparent; - border: 0; -} - -.markdown-body .full-commit .btn-outline:not(:disabled):hover { - color: #005cc5; - border-color: #005cc5; -} - -.markdown-body kbd { - display: inline-block; - padding: 3px 5px; - font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - line-height: 10px; - color: #444d56; - vertical-align: middle; - background-color: #fafbfc; - border: solid 1px #d1d5da; - border-bottom-color: #c6cbd1; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #c6cbd1; -} - -.markdown-body :checked+.radio-label { - position: relative; - z-index: 1; - border-color: #0366d6; -} - -.markdown-body .task-list-item { - list-style-type: none; -} - -.markdown-body .task-list-item+.task-list-item { - margin-top: 3px; -} - -.markdown-body .task-list-item input { - margin: 0 0.2em 0.25em -1.6em; - vertical-align: middle; -} - -.markdown-body hr { - border-bottom-color: #eee; -} - -.command { - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, - monospace; - font-size: 16px; - padding-left: 40px; - -} - -.command h1 { - border: none; - margin-left: -40px; -} - -.command h2 { - border: none; - margin-top: 2em; - margin-left: -40px; - font-size: 18px; -} - -.command>ul { - padding-left: 0; -} - -.command ul { - list-style-type: none; -} - -.command table { - margin: 2em 0 1em; - display: block; - width: 100%; - overflow: auto; - border-collapse: collapse; -} - -.command table th { - font-weight: 600; -} - -.command table th, -.command table td { - padding: 6px 13px; - border: 1px solid #dfe2e5; -} - -.command table tr { - background-color: #fff; - border-top: 1px solid #c6cbd1; -} - -.command table tr:nth-child(2n) { - background-color: #f6f8fa; -} - - -` diff --git a/vendor/github.com/smallstep/cli-utils/usage/help.go b/vendor/github.com/smallstep/cli-utils/usage/help.go deleted file mode 100644 index eef3273..0000000 --- a/vendor/github.com/smallstep/cli-utils/usage/help.go +++ /dev/null @@ -1,191 +0,0 @@ -package usage - -import ( - "fmt" - "strings" - - "github.com/urfave/cli" -) - -// HelpCommandAction is the action function of the overwritten help command. -var HelpCommandAction = cli.ActionFunc(helpAction) - -// HelpCommand overwrites default urfvafe/cli help command to support one or -// multiple subcommands like: -// -// step help -// step help crypto -// step help crypto jwt -// step help crypto jwt sign -// ... -func HelpCommand() cli.Command { - return cli.Command{ - Name: "help", - Aliases: []string{"h"}, - Usage: "display help for the specified command or command group", - UsageText: "**step help** <command>", - Description: `**step help** command displays help for a command or command group. - -## EXAMPLES - -Display help for **step ca certificate**: -''' -$ step help ca certificate -''' - -Display help for **step ssh**: -''' -$ step help ssh -'''`, - Action: HelpCommandAction, - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "http", - Usage: "HTTP service address (e.g., ':8080')", - }, - cli.StringFlag{ - Name: "html", - Usage: "The export <directory> for HTML docs.", - }, - cli.StringFlag{ - Name: "markdown", - Usage: "The export <directory> for Markdown docs.", - }, - cli.BoolFlag{ - Name: "report", - Usage: "Writes a JSON report to the HTML docs directory.", - }, - }, - } -} - -func helpAction(ctx *cli.Context) error { - // use html version - if ctx.IsSet("http") { - return httpHelpAction(ctx) - } - - if ctx.IsSet("html") { - return htmlHelpAction(ctx) - } - - if ctx.IsSet("markdown") { - return markdownHelpAction(ctx) - } - - args := ctx.Args() - if args.Present() { - last := len(args) - 1 - lastName := args[last] - subcmd := ctx.App.Commands - parent := createParentCommand(ctx) - - for _, name := range args[:last] { - for _, cmd := range subcmd { - if cmd.HasName(name) { - parent = cmd - subcmd = cmd.Subcommands - break - } - } - } - - for _, cmd := range subcmd { - if !cmd.HasName(lastName) { - continue - } - cmd.HelpName = fmt.Sprintf("%s %s", ctx.App.HelpName, strings.Join(args, " ")) - parent.HelpName = fmt.Sprintf("%s %s", ctx.App.HelpName, strings.Join(args[:last], " ")) - - ctx.Command = cmd - if len(cmd.Subcommands) == 0 { - ctx.App = createCliApp(ctx, parent) - return cli.ShowCommandHelp(ctx, lastName) - } - - ctx.App = createCliApp(ctx, cmd) - return cli.ShowCommandHelp(ctx, "") - } - - return cli.NewExitError(fmt.Sprintf("No help topic for '%s %s'", ctx.App.Name, strings.Join(args, " ")), 3) - } - - cli.ShowAppHelp(ctx) - return nil -} - -// createParentCommand returns a command representation of the app. -func createParentCommand(ctx *cli.Context) cli.Command { - return cli.Command{ - Name: ctx.App.Name, - HelpName: ctx.App.HelpName, - Usage: ctx.App.Usage, - UsageText: ctx.App.UsageText, - ArgsUsage: ctx.App.ArgsUsage, - Description: ctx.App.Description, - Subcommands: ctx.App.Commands, - Flags: ctx.App.Flags, - } -} - -// createCliApp is re-implementation of urfave/cli method (in command.go): -// -// func (c Command) startApp(ctx *Context) error -// -// It lets us show the subcommands when help is executed like: -// -// step help foo -// step help foo bar -// ... -func createCliApp(ctx *cli.Context, cmd cli.Command) *cli.App { - app := cli.NewApp() - app.Metadata = ctx.App.Metadata - - // set the name and usage - app.Name = cmd.HelpName - app.HelpName = cmd.HelpName - - app.Usage = cmd.Usage - app.UsageText = cmd.UsageText - app.Description = cmd.Description - app.ArgsUsage = cmd.ArgsUsage - - // set CommandNotFound - app.CommandNotFound = ctx.App.CommandNotFound - app.CustomAppHelpTemplate = cmd.CustomHelpTemplate - - // set the flags and commands - app.Commands = cmd.Subcommands - app.Flags = cmd.Flags - - app.Version = ctx.App.Version - app.Compiled = ctx.App.Compiled - app.Author = ctx.App.Author - app.Email = ctx.App.Email - app.Writer = ctx.App.Writer - app.ErrWriter = ctx.App.ErrWriter - - // Do not show help or version on subcommands - app.HideHelp = true - app.HideVersion = true - - // bash completion - app.EnableBashCompletion = ctx.App.EnableBashCompletion - if cmd.BashComplete != nil { - app.BashComplete = cmd.BashComplete - } - - // set the actions - app.Before = cmd.Before - app.After = cmd.After - - if cmd.Action != nil { - app.Action = cmd.Action - } else { - app.Action = helpAction - } - app.OnUsageError = cmd.OnUsageError - - app.Setup() - return app -} diff --git a/vendor/github.com/smallstep/cli-utils/usage/html.go b/vendor/github.com/smallstep/cli-utils/usage/html.go deleted file mode 100644 index b2aaeb8..0000000 --- a/vendor/github.com/smallstep/cli-utils/usage/html.go +++ /dev/null @@ -1,351 +0,0 @@ -package usage - -import ( - "fmt" - "net/http" - "os" - "path" - "strings" - "time" - - "github.com/urfave/cli" - - "github.com/smallstep/cli-utils/errs" -) - -func httpHelpAction(ctx *cli.Context) error { - addr := ctx.String("http") - if addr == "" { - return errs.RequiredFlag(ctx, "http") - } - - fmt.Printf("Serving HTTP on %s ...\n", addr) - server := http.Server{ - Addr: addr, - Handler: &htmlHelpHandler{ - cliApp: ctx.App, - }, - ReadHeaderTimeout: 15 * time.Second, - } - return server.ListenAndServe() -} - -func markdownHelpAction(ctx *cli.Context) error { - dir := path.Clean(ctx.String("markdown")) - if err := os.MkdirAll(dir, 0755); err != nil { - return errs.FileError(err, dir) - } - - // app index - index := path.Join(dir, "README.mdx") - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - markdownHelpPrinter(w, mdAppHelpTemplate, "", ctx.App) - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - // Subcommands - for _, cmd := range ctx.App.Commands { - if err := markdownHelpCommand(ctx.App, cmd, cmd, path.Join(dir, cmd.Name)); err != nil { - return err - } - } - return nil -} - -func markdownHelpCommand(app *cli.App, cmd, parent cli.Command, base string) error { - if err := os.MkdirAll(base, 0755); err != nil { - return errs.FileError(err, base) - } - - fileName := "README.mdx" - - index := path.Join(base, fileName) - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - - parentName := parent.HelpName - if cmd.HelpName == parent.HelpName { - parentName = "step" - } - - if len(cmd.Subcommands) == 0 { - markdownHelpPrinter(w, mdCommandHelpTemplate, parentName, cmd) - return errs.FileError(w.Close(), index) - } - - ctx := cli.NewContext(app, nil, nil) - ctx.App = createCliApp(ctx, cmd) - markdownHelpPrinter(w, mdSubcommandHelpTemplate, parentName, ctx.App) - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - for _, sub := range cmd.Subcommands { - sub.HelpName = fmt.Sprintf("%s %s", cmd.HelpName, sub.Name) - if err := markdownHelpCommand(app, sub, cmd, path.Join(base, sub.Name)); err != nil { - return err - } - } - - return nil -} - -func htmlHelpAction(ctx *cli.Context) error { - dir := path.Clean(ctx.String("html")) - - if err := os.MkdirAll(dir, 0755); err != nil { - return errs.FileError(err, dir) - } - - // app index - index := path.Join(dir, "index.html") - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - - tophelp := htmlHelpPrinter(w, mdAppHelpTemplate, ctx.App) - var report *Report - if ctx.IsSet("report") { - report = NewReport(ctx.App.Name, tophelp) - } - - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - // css style - cssFile := path.Join(dir, "style.css") - //nolint:gosec // not security sensitive - if err := os.WriteFile(cssFile, []byte(css), 0666); err != nil { - return errs.FileError(err, cssFile) - } - - // Subcommands - for _, cmd := range ctx.App.Commands { - if err := htmlHelpCommand(ctx.App, cmd, path.Join(dir, cmd.Name), report); err != nil { - return err - } - } - - // report - if report != nil { - repjson := path.Join(dir, "report.json") - rjw, err := os.Create(repjson) - if err != nil { - return errs.FileError(err, repjson) - } - - if err := report.Write(rjw); err != nil { - return err - } - - if err := rjw.Close(); err != nil { - return errs.FileError(err, repjson) - } - } - - return nil -} - -func htmlHelpCommand(app *cli.App, cmd cli.Command, base string, report *Report) error { - if err := os.MkdirAll(base, 0755); err != nil { - return errs.FileError(err, base) - } - - index := path.Join(base, "index.html") - w, err := os.Create(index) - if err != nil { - return errs.FileError(err, index) - } - - if len(cmd.Subcommands) == 0 { - cmdhelp := htmlHelpPrinter(w, mdCommandHelpTemplate, cmd) - - if report != nil { - report.Process(cmd.HelpName, cmdhelp) - } - - return errs.FileError(w.Close(), index) - } - - ctx := cli.NewContext(app, nil, nil) - ctx.App = createCliApp(ctx, cmd) - subhelp := htmlHelpPrinter(w, mdSubcommandHelpTemplate, ctx.App) - - if report != nil { - report.Process(cmd.HelpName, subhelp) - } - - if err := w.Close(); err != nil { - return errs.FileError(err, index) - } - - for _, sub := range cmd.Subcommands { - sub.HelpName = fmt.Sprintf("%s %s", cmd.HelpName, sub.Name) - if err := htmlHelpCommand(app, sub, path.Join(base, sub.Name), report); err != nil { - return err - } - } - - return nil -} - -type htmlHelpHandler struct { - cliApp *cli.App -} - -func (h *htmlHelpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - ctx := cli.NewContext(h.cliApp, nil, nil) - - // clean request URI - requestURI := path.Clean(req.RequestURI) - if requestURI == "/" { - htmlHelpPrinter(w, mdAppHelpTemplate, ctx.App) - return - } - - if requestURI == "/style.css" { - w.Header().Set("Content-Type", `text/css; charset="utf-8"`) - w.Write([]byte(css)) - return - } - - args := strings.Split(requestURI, "/") - last := len(args) - 1 - lastName := args[last] - subcmd := ctx.App.Commands - for _, name := range args[:last] { - for _, cmd := range subcmd { - if cmd.HasName(name) { - subcmd = cmd.Subcommands - break - } - } - } - - for _, cmd := range subcmd { - if !cmd.HasName(lastName) { - continue - } - cmd.HelpName = fmt.Sprintf("%s %s", ctx.App.HelpName, strings.Join(args, " ")) - - ctx.Command = cmd - if len(cmd.Subcommands) == 0 { - htmlHelpPrinter(w, mdCommandHelpTemplate, cmd) - return - } - - ctx.App = createCliApp(ctx, cmd) - htmlHelpPrinter(w, mdSubcommandHelpTemplate, ctx.App) - return - } - - http.NotFound(w, req) -} - -// AppHelpTemplate contains the modified template for the main app -var mdAppHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -'''raw -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .Commands}} <command>{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments]{{end}}{{end}} -''' -{{- if .Description}} - -## DESCRIPTION -{{.Description}}{{end}}{{if .VisibleCommands}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -| Name | Usage | -|---|---|{{range .VisibleCommands}} -| **[{{join .Names ", "}}]({{.Name}}/)** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}}{{end}} - -## OPTIONS - -{{range $index, $option := .VisibleFlags}}{{if $index}} -{{end}}{{$option}} -{{end}}{{end}}{{if .Copyright}}{{if len .Authors}} - -## AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: - -{{range $index, $author := .Authors}}{{if $index}} -{{end}}{{$author}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} - -## VERSION - -{{.Version}}{{end}}{{end}} - -## COPYRIGHT - -{{.Copyright}} -{{end}} -` - -// SubcommandHelpTemplate contains the modified template for a sub command -// Note that the weird "|||\n|---|---|" syntax sets up a markdown table with empty headers. -var mdSubcommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -'''raw -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}** <command>{{if .VisibleFlags}} [options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments]{{end}}{{end}} -''' -{{- if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -| Name | Usage | -|---|---|{{range .VisibleCommands}} -| **[{{join .Names ", "}}]({{.Name}}/)** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` - -// CommandHelpTemplate contains the modified template for a command -var mdCommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -'''raw -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .VisibleFlags}} [options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments]{{end}}{{end}} -''' -{{- if .Category}} - -## CATEGORY - -{{.Category}}{{end}}{{if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` diff --git a/vendor/github.com/smallstep/cli-utils/usage/printer.go b/vendor/github.com/smallstep/cli-utils/usage/printer.go deleted file mode 100644 index 0a09680..0000000 --- a/vendor/github.com/smallstep/cli-utils/usage/printer.go +++ /dev/null @@ -1,235 +0,0 @@ -package usage - -import ( - "bytes" - "fmt" - "io" - "regexp" - "strings" - "text/template" - "unicode" - - "github.com/urfave/cli" - - md "github.com/smallstep/cli-utils/pkg/blackfriday" -) - -var sectionRe = regexp.MustCompile(`(?m:^##)`) -var sectionNameRe = regexp.MustCompile(`(?m:^## [^\n]+)`) -var indentRe = regexp.MustCompile(`(?m:^:[^\n]+)`) -var definitionListRe = regexp.MustCompile(`(?m:^[\t ]+\*\*[^\*]+\*\*[^\n]*\s+:[^\n]+)`) - -//var sectionRe = regexp.MustCompile(`^## [^\n]*$`) - -type frontmatterData struct { - Data interface{} - Parent string - Children []string -} - -// HelpPrinter overwrites cli.HelpPrinter and prints the formatted help to the terminal. -func HelpPrinter(w io.Writer, templ string, data interface{}) { - b := helpPreprocessor(w, templ, data, false) - w.Write(Render(b)) -} - -func htmlHelpPrinter(w io.Writer, templ string, data interface{}) []byte { - b := helpPreprocessor(w, templ, data, true) - w.Write([]byte(`<html><head><title>step command line documentation</title>`)) - w.Write([]byte(`<link href="/style.css" rel="stylesheet" type="text/css">`)) - w.Write([]byte(`</head><body><div class="wrapper markdown-body command">`)) - html := md.Run(b) - w.Write(html) - w.Write([]byte(`</div></body></html>`)) - - return html -} - -func markdownHelpPrinter(w io.Writer, templ, parent string, data interface{}) { - b := helpPreprocessor(w, templ, data, true) - - frontmatter := frontmatterData{ - Data: data, - Parent: parent, - } - - if app, ok := data.(*cli.App); ok { - for _, cmd := range app.Commands { - frontmatter.Children = append(frontmatter.Children, cmd.Name) - } - } - - var frontMatterTemplate = `--- -layout: auto-doc -category: reference -title: {{.Data.HelpName}} -menu: - docs: -{{- if .Parent}} - parent: {{.Parent}} -{{- end }} -{{- if .Children }} - children: -{{- range .Children }} - - {{.}} -{{- end }} -{{- end }} ---- - -` - t, err := template.New("frontmatter").Parse(frontMatterTemplate) - if err != nil { - panic(err) - } - err = t.Execute(w, frontmatter) - if err != nil { - panic(err) - } - w.Write(b) -} - -func helpPreprocessor(_ io.Writer, templ string, data interface{}, applyRx bool) []byte { - buf := new(bytes.Buffer) - cli.HelpPrinterCustom(buf, templ, data, nil) - //w.Write(buf.Bytes()) - // s := string(markdownify(buf.Bytes())) - s := markdownify(buf) - // Move the OPTIONS section to the right place. urfave puts them at the end - // of the file, we want them to be after POSITIONAL ARGUMENTS, DESCRIPTION, - // USAGE, or NAME (in that order, depending on which sections exist). - optLoc := strings.Index(s, "## OPTIONS") - if optLoc != -1 { - optEnd := findSectionEnd("OPTIONS", s) - if optEnd != -1 { - options := s[optLoc:optEnd] - s = s[:optLoc] + s[optEnd:] - if newLoc := findSectionEnd("POSITIONAL ARGUMENTS", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else if newLoc := findSectionEnd("DESCRIPTION", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else if newLoc := findSectionEnd("USAGE", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else if newLoc := findSectionEnd("NAME", s); newLoc != -1 { - s = s[:newLoc] + options + s[newLoc:] - } else { - // Keep it at the end I guess :/. - s += options - } - } - } - - if applyRx { - // Keep capitalized only the first letter in arguments names. - s = sectionNameRe.ReplaceAllStringFunc(s, func(s string) string { - return s[0:4] + strings.ToLower(s[4:]) - }) - // Remove `:` at the start of a line. - s = indentRe.ReplaceAllStringFunc(s, func(s string) string { - return strings.TrimSpace(s[1:]) - }) - // Convert lines like: - // **Foo** - // : Bar zar ... - // To: - // - **Foo**: Bar zar ... - s = definitionListRe.ReplaceAllStringFunc(s, func(s string) string { - i := strings.Index(s, "\n") - j := strings.Index(s, ":") - return "- " + strings.TrimSpace(s[:i]) + ": " + strings.TrimSpace(s[j+1:]) - }) - } - - return []byte(s) -} - -func findSectionEnd(h, s string) int { - start := strings.Index(s, fmt.Sprintf("## %s", h)) - if start == -1 { - return start - } - nextSection := sectionRe.FindStringIndex(s[start+2:]) - if nextSection == nil { - return len(s) - } - return start + 2 + nextSection[0] -} - -// Convert some stuff that we can't easily write in help files because -// -// backticks and raw strings don't mix: -// -// - "<foo>" to "`foo`" -// - "”'" to "```" -func markdownify(r *bytes.Buffer) string { - const escapeByte = byte('\\') - var last byte - var inCode bool - - w := new(bytes.Buffer) - for { - b, err := r.ReadByte() - if err != nil { - return w.String() - } - loop: - switch b { - case '<': - if last != escapeByte && !inCode { - w.WriteByte('`') - } else { - w.WriteByte(b) - } - case '>': - if last != escapeByte && !inCode { - w.WriteByte('`') - } else { - w.WriteByte(b) - } - case '\'': - b1, _ := r.ReadByte() - b2, _ := r.ReadByte() - if b1 == b && b2 == b { - w.WriteString("```") - if !inCode { - if n, _, err := r.ReadRune(); err == nil { - if unicode.IsSpace(n) { - w.WriteString("shell") - } - r.UnreadRune() - } - } - inCode = !inCode - } else { - // We can only unread the last one (b2) - w.WriteByte(b) - r.UnreadByte() - b = b1 - last = b - goto loop - } - case '*': - if inCode { - if b1, _ := r.ReadByte(); b1 != '*' { - w.WriteByte(b) - w.UnreadByte() - } - } else { - w.WriteByte(b) - } - case escapeByte: - if last == escapeByte { - w.WriteByte(escapeByte) - b = 0 - } else if n, _, err := r.ReadRune(); err == nil { - if unicode.IsSpace(n) { - w.WriteByte(escapeByte) - } - r.UnreadRune() - } - case 0: // probably because io.EOF - default: - w.WriteByte(b) - } - last = b - } -} diff --git a/vendor/github.com/smallstep/cli-utils/usage/renderer.go b/vendor/github.com/smallstep/cli-utils/usage/renderer.go deleted file mode 100644 index 7fb1506..0000000 --- a/vendor/github.com/smallstep/cli-utils/usage/renderer.go +++ /dev/null @@ -1,373 +0,0 @@ -package usage - -import ( - "bufio" - "bytes" - "fmt" - "io" - "regexp" - "strings" - "text/tabwriter" - "unicode" - - "github.com/mgutz/ansi" - - md "github.com/smallstep/cli-utils/pkg/blackfriday" -) - -// Render renders the given data with a custom markdown renderer. -func Render(b []byte) []byte { - return md.Run(b, md.WithRenderer(&Renderer{6, 0, nil, nil, false})) -} - -var colorEscapeRe = regexp.MustCompile(`\033\[\d*(;\d*)?m?\]?`) -var maxLineLength = 80 - -func stripColors(b []byte) []byte { - return colorEscapeRe.ReplaceAll(b, []byte("")) -} - -type item struct { - flags md.ListType - term []byte - definitions [][]byte -} - -type list struct { - items []item - flags md.ListType - parent *list -} - -/* TODO: commented because unused -func (l *list) isUnordered() bool { - return !l.isOrdered() && !l.isDefinition() -} - -func (l *list) isOrdered() bool { - return l.flags&md.ListTypeOrdered != 0 -} - -func (l *list) containsBlock() bool { - // TODO: Not sure if we have to check every item or if it gets - // automatically set on the list? - return l.flags&md.ListItemContainsBlock != 0 -} -*/ - -func (l *list) isDefinition() bool { - return l.flags&md.ListTypeDefinition != 0 -} - -type bufqueue struct { - w io.Writer - buf *bytes.Buffer - next *bufqueue - mode RenderMode -} - -// RenderMode enumerates different line breaks modes. -type RenderMode int - -const ( - // RenderModeKeepBreaks will keep the line breaks in the docs. - RenderModeKeepBreaks RenderMode = iota - // RenderModeBreakLines will automatically wrap the lines. - RenderModeBreakLines -) - -// Renderer implements a custom markdown renderer for blackfriday. -type Renderer struct { - depth int - listdepth int - list *list - out *bufqueue - inpara bool -} - -func (r *Renderer) write(b []byte) { - r.out.w.Write(b) -} - -func (r *Renderer) printf(s string, a ...interface{}) { - fmt.Fprintf(r.out.w, s, a...) -} - -func (r *Renderer) capture(mode RenderMode) { - buf := new(bytes.Buffer) - r.out = &bufqueue{buf, buf, r.out, mode} -} - -func (r *Renderer) finishCapture() *bytes.Buffer { - buf := r.out.buf - r.out = r.out.next - return buf -} - -func (r *Renderer) inParagraph() bool { - return r.inpara -} - -/* TODO: commented because unused -func (r *Renderer) inList() bool { - return r.list != nil -} -*/ - -func (r *Renderer) renderParagraphKeepBreaks(buf *bytes.Buffer) { - scanner := bufio.NewScanner(buf) - for scanner.Scan() { - r.printf(strings.Repeat(" ", r.depth)+"%s\n", scanner.Text()) - } -} - -func (r *Renderer) renderParagraphBreakLines(buf *bytes.Buffer, maxlen int) { - maxlen -= r.depth - scanner := bufio.NewScanner(buf) - scanner.Split(bufio.ScanWords) - line := []string{} - length := 0 - for scanner.Scan() { - word := scanner.Text() - wordLength := len(stripColors([]byte(word))) - // Print the line if we've got a collection of words over 80 characters, or if - // we have a single word that is over 80 characters on an otherwise empty line. - switch { - case length+wordLength > maxlen: - r.printf(strings.Repeat(" ", r.depth)+"%s\n", strings.Join(line, " ")) - line = []string{word} - length = wordLength - case length == 0 && wordLength > maxlen: - r.printf(strings.Repeat(" ", r.depth)+"%s\n", word) - default: - line = append(line, word) - length += wordLength + 1 // Plus one for space - } - } - if len(line) > 0 { - r.printf(strings.Repeat(" ", r.depth)+"%s\n", strings.Join(line, " ")) - } -} - -func (r *Renderer) renderParagraph(buf *bytes.Buffer) { - switch r.out.mode { - case RenderModeKeepBreaks: - r.renderParagraphKeepBreaks(buf) - case RenderModeBreakLines: - r.renderParagraphBreakLines(buf, maxLineLength) - } -} - -// RenderNode implements blackfriday.Renderer interface. -func (r *Renderer) RenderNode(w io.Writer, node *md.Node, entering bool) md.WalkStatus { - if r.out == nil { - r.out = &bufqueue{w, nil, nil, RenderModeBreakLines} - } - - switch node.Type { - case md.Paragraph: - // Alternative idea here: call r.RenderNode() with our new buffer as - // `w`. In the `else` condition here render to the outter buffer and - // always return md.Terminate. So when we enter a paragraph we start - // parsing with a new output buffer and capture the output. - if entering { - if r.inParagraph() { - panic("already in paragraph") - } - r.inpara = true - //r.printf(out, "[paragraph:") - r.capture(r.out.mode) - } else { - r.renderParagraph(r.finishCapture()) - // Write a newline unless the parent node is a definition list term. - if node.Parent.Type != md.Item || node.Parent.ListFlags&md.ListTypeTerm == 0 { - r.printf("\n") - } - r.inpara = false - //r.printf(w, ":paragraph]") - } - case md.Text: - // TODO: is this necessary? I think all text is in a paragraph. - if r.inParagraph() { - r.write(node.Literal) - } else { - s := strings.ReplaceAll(string(node.Literal), "\n", "\n"+strings.Repeat(" ", r.depth)) - r.printf(s) //nolint:govet // allow non-constant - } - case md.Heading: - if entering { - r.printf(ansi.ColorCode("default+bh")) //nolint:govet // allow non-constant - } else { - r.printf(ansi.Reset) - r.printf("\n") - } - case md.Link: - if entering { - r.printf(ansi.ColorCode("default+b")) //nolint:govet // allow non-constant - //r.printf("\033[2m") // Dim - } else { - r.printf(ansi.Reset) - } - case md.Strong: - if entering { - r.printf(ansi.ColorCode("default+bh")) //nolint:govet // allow non-constant - } else { - r.printf(ansi.Reset) - } - case md.Emph: - if entering { - r.printf(ansi.ColorCode("default+u")) //nolint:govet // allow non-constant - } else { - r.printf(ansi.Reset) - } - case md.Code: - r.printf(ansi.ColorCode("default+u")) //nolint:govet // allow non-constant - r.write(node.Literal) - r.printf(ansi.Reset) - case md.List: - if entering { - r.listdepth++ - r.list = &list{[]item{}, node.ListFlags, r.list} - //r.printf("[list (type %s:", node.ListData.ListFlags) - } else { - if r.listdepth > 1 && r.list.isDefinition() { - w := new(tabwriter.Writer) - w.Init(r.out.w, 0, 8, 4, ' ', tabwriter.StripEscape) - for _, item := range r.list.items { - fmt.Fprint(w, strings.TrimRight(string(item.term), " \n")) - fmt.Fprint(w, "\n") - for _, def := range item.definitions { - fmt.Fprint(w, strings.TrimRight(string(def), " \n")) - } - fmt.Fprintf(w, "\n\n") - } - w.Flush() - } else { - ordered := (node.ListFlags&md.ListTypeOrdered != 0) - unordered := (node.ListFlags&md.ListTypeOrdered == 0 && node.ListFlags&md.ListTypeDefinition == 0) - for i, item := range r.list.items { - if ordered || unordered { - p := bytes.IndexFunc(item.term, func(r rune) bool { return !unicode.IsSpace(r) }) - switch { - case ordered: // add numbers on ordered lists - item.term = append(item.term[:p], append([]byte(fmt.Sprintf("%d. ", i+1)), item.term[p:]...)...) - case unordered: // add bullet points on unordered lists - item.term = append(item.term[:p], append([]byte("• "), item.term[p:]...)...) - } - } - - r.write(item.term) - for _, def := range item.definitions { - r.write(def) - } - } - } - r.listdepth-- - r.list = r.list.parent - //r.printf(":list]") - } - case md.Item: - incdepth := 4 - //ltype := "normal" - if node.ListFlags&md.ListTypeTerm != 0 { - // Nested definition list terms get indented two spaces. Non-nested - // definition list terms are not indented. - if r.listdepth > 1 { - incdepth = 2 - } else { - incdepth = 0 - } - //ltype = "dt" - } else if node.ListFlags&md.ListTypeDefinition != 0 { - incdepth = 4 - //ltype = "dd" - } - - if entering { - //fmt.Fprintf(out, "[list item %s:", ltype) - r.depth += incdepth - if r.listdepth > 1 && r.list.isDefinition() { - r.capture(RenderModeKeepBreaks) - } else { - r.capture(RenderModeBreakLines) - } - if !r.list.isDefinition() || node.ListFlags&md.ListTypeTerm != 0 { - r.list.items = append(r.list.items, item{node.ListFlags, nil, nil}) - } - } else { - //fmt.Fprintf(out, ":list item]") - r.depth -= incdepth - buf := r.finishCapture() - if r.list.isDefinition() && node.ListFlags&md.ListTypeTerm == 0 { - i := len(r.list.items) - 1 - r.list.items[i].definitions = append(r.list.items[i].definitions, buf.Bytes()) - } else { - r.list.items[len(r.list.items)-1].term = buf.Bytes() - } - } - case md.Table: - if entering { - r.capture(RenderModeKeepBreaks) - w := new(tabwriter.Writer) - w.Init(r.out.w, 1, 8, 2, ' ', tabwriter.StripEscape) - r.out.w = w - } else { - r.out.w.(*tabwriter.Writer).Flush() - buf := r.finishCapture() - r.renderParagraphKeepBreaks(buf) - r.printf("\n") - } - case md.TableBody: - // Do nothing. - case md.TableHead: - if entering { - r.capture(r.out.mode) - } else { - // Markdown doens't have a way to create a table without headers. - // We've opted to fix that here by not rendering headers at all if - // they're empty. - result := r.finishCapture().Bytes() - if strings.TrimSpace(string(stripColors(result))) != "" { - parts := strings.Split(strings.TrimRight(string(result), "\t\n"), "\t") - for i := 0; i < len(parts); i++ { - parts[i] = "\xff" + ansi.ColorCode("default+bh") + "\xff" + parts[i] + "\xff" + ansi.Reset + "\xff" - } - r.printf(strings.Join(parts, "\t") + "\t\n") //nolint:govet // allow non-constant - } - } - case md.TableRow: - if entering { - r.capture(r.out.mode) - } else { - // Escape any colors in the row before writing to the - // tabwriter, otherwise they screw up the width calculations. The - // escape character for tabwriter is \xff. - result := r.finishCapture().Bytes() - result = colorEscapeRe.ReplaceAll(result, []byte("\xff$0\xff")) - r.write(result) - r.printf("\n") - } - case md.TableCell: - if !entering { - r.printf("\t") - } - case md.CodeBlock: - r.depth += 4 - r.renderParagraphKeepBreaks(bytes.NewBuffer(node.Literal)) - r.printf("\n") - r.depth -= 4 - case md.Document: - default: - r.printf("unknown block %s:", node.Type) - r.write(node.Literal) - } - //w.Write([]byte(fmt.Sprintf("node<%s; %t>", node.Type, entering))) - //w.Write(node.Literal) - return md.GoToNext -} - -// RenderHeader implements blackfriday.Renderer interface. -func (r *Renderer) RenderHeader(io.Writer, *md.Node) {} - -// RenderFooter implements blackfriday.Renderer interface. -func (r *Renderer) RenderFooter(io.Writer, *md.Node) {} diff --git a/vendor/github.com/smallstep/cli-utils/usage/report.go b/vendor/github.com/smallstep/cli-utils/usage/report.go deleted file mode 100644 index 14ed250..0000000 --- a/vendor/github.com/smallstep/cli-utils/usage/report.go +++ /dev/null @@ -1,148 +0,0 @@ -package usage - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "regexp" - "strings" - - "golang.org/x/net/html" -) - -// Section keeps track of individual sections -type Section struct { - Command string `json:"command"` - Name string `json:"name"` - Text string `json:"text"` - Words int `json:"words"` - Lines int `json:"lines"` - Sections []*Section `json:"sections"` -} - -// Report holds together a report of sections -type Report struct { - Report []*Section `json:"report"` -} - -// NewReport returns report based on raw -func NewReport(command string, top []byte) *Report { - report := Report{} - report.Process(command, top) - - return &report -} - -// Write serializes the report to json -func (report *Report) Write(w io.Writer) error { - j, err := json.MarshalIndent(report, "", " ") - - if err != nil { - return err - } - - w.Write(j) - - return nil -} - -// Process adds a html based help page to the report -func (report *Report) Process(command string, raw []byte) error { - r := bytes.NewBuffer(raw) - doc, err := html.Parse(r) - - if err != nil { - return err - } - - if doc.FirstChild.Type != html.ElementNode || - doc.FirstChild.Data != "html" || - doc.FirstChild.FirstChild.NextSibling.Data != "body" { - return errors.New("error parsing raw html") - } - - body := doc.FirstChild.FirstChild.NextSibling - - report.addSection(command, body.FirstChild, nil) - - return nil -} - -func (report *Report) addSection(command string, node *html.Node, section *Section) (*html.Node, *Section) { - if node == nil || - node.Type != html.ElementNode || - node.Data != "h2" { - return nil, nil - } - - text, next := report.processNode(node) - words := strings.Fields(text) - lines := strings.Split(text, "\n") - - s := Section{ - Command: command, - Name: node.FirstChild.Data, - Text: text, - Words: len(words), - Lines: len(lines), - } - - if section == nil { - report.Report = append(report.Report, &s) - return report.addSection(command, next, &s) - } - - section.Sections = append(section.Sections, &s) - return report.addSection(command, next, section) -} - -func (report *Report) processNode(node *html.Node) (string, *html.Node) { - text := "" - current := node.NextSibling - - r := regexp.MustCompile(`<[^>]*>`) - - for current != nil { - var buf bytes.Buffer - w := io.Writer(&buf) - html.Render(w, current) - - notags := r.ReplaceAllString(buf.String(), "") - clean := strings.TrimSpace(notags) - - if text != "" && clean != "" { - text = fmt.Sprintf("%s %s", text, clean) - } else if clean != "" { - text = clean - } - - current = current.NextSibling - if current == nil { - return text, nil - } else if current.Type == html.ElementNode && - current.Data == "h2" { - node = current - current = nil - } - } - - return text, node -} - -// PerHeadline returns all sections across commands/pages with the same headline -func (report *Report) PerHeadline(headline string) []Section { - var results []Section - for _, top := range report.Report { - for _, section := range top.Sections { - if section.Name != headline { - continue - } - - results = append(results, *section) - } - } - - return results -} diff --git a/vendor/github.com/smallstep/cli-utils/usage/usage.go b/vendor/github.com/smallstep/cli-utils/usage/usage.go deleted file mode 100644 index 9ed88d9..0000000 --- a/vendor/github.com/smallstep/cli-utils/usage/usage.go +++ /dev/null @@ -1,214 +0,0 @@ -package usage - -import ( - "bytes" - "fmt" - "html" - "strconv" - "strings" - "text/template" -) - -var usageTextTempl = " {{.Name}}\n {{.Usage}} {{if .Required}}(Required){{else}}(Optional){{end}}{{if .Multiple}} (Multiple can be specified){{end}}\n" -var templ *template.Template - -func init() { - templ = template.Must(template.New("usageText").Parse(usageTextTempl)) -} - -// Argument specifies the Name, Usage, and whether or not an Argument is -// required or not -type Argument struct { - Required bool - Multiple bool - Name string - Usage string -} - -// Decorate returns the name of an Argument and decorates it with notation to -// indicate whether its required or not -func (a Argument) Decorate() string { - name := a.Name - if a.Multiple { - name += "(s)..." - } - if a.Required { - return fmt.Sprintf("<%s>", name) - } - - return fmt.Sprintf("[%s]", name) -} - -// Arguments is an array of Argument structs that specify which arguments are -// accepted by a Command -type Arguments []Argument - -// UsageText returns the value of the UsageText property for a cli.Command for -// these arguments -func (args Arguments) UsageText() string { - var buf bytes.Buffer - for _, a := range args { - data := map[string]interface{}{ - "Name": a.Decorate(), - "Multiple": a.Multiple, - "Required": a.Required, - "Usage": a.Usage, - } - - err := templ.Execute(&buf, data) - if err != nil { - panic(fmt.Sprintf("Could not generate args template for %s: %s", a.Name, err)) - } - } - - return "\n\n" + buf.String() -} - -// ArgsUsage returns the value of the ArgsUsage property for a cli.Command for -// these arguments -func (args Arguments) ArgsUsage() string { - out := "" - for i, a := range args { - out += a.Decorate() - if i < len(args)-1 { - out += " " - } - } - - return out -} - -// AppHelpTemplate contains the modified template for the main app -var AppHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .Commands}} <command>{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}_[arguments]_{{end}}{{end}}{{if .Description}} - -## DESCRIPTION -{{.Description}}{{end}}{{if .VisibleCommands}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -||| -|---|---|{{range .VisibleCommands}} -| **{{join .Names ", "}}** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}}{{end}} - -## OPTIONS - -{{range $index, $option := .VisibleFlags}}{{if $index}} -{{end}}{{$option}} -{{end}}{{end}}{{if .Copyright}}{{if len .Authors}} - -## AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: - -{{range $index, $author := .Authors}}{{if $index}} -{{end}}{{$author}}{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} - -## ONLINE - -This documentation is available online at https://smallstep.com/docs/cli - -## VERSION - -{{.Version}}{{end}}{{end}} - -## COPYRIGHT - -{{.Copyright}} - -## FEEDBACK ` + - html.UnescapeString("&#"+strconv.Itoa(128525)+";") + " " + - html.UnescapeString("&#"+strconv.Itoa(127867)+";") + - ` - -The **step** utility is not instrumented for usage statistics. It does not phone home. -But your feedback is extremely valuable. Any information you can provide regarding how you’re using **step** helps. -Please send us a sentence or two, good or bad: **feedback@smallstep.com** or ask in [GitHub Discussions](https://github.com/smallstep/certificates/discussions). -{{end}} -` - -// SubcommandHelpTemplate contains the modified template for a sub command -// Note that the weird "|||\n|---|---|" syntax sets up a markdown table with empty headers. -var SubcommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}** <command>{{if .VisibleFlags}} _[options]_{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}_[arguments]_{{end}}{{end}}{{if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}} - -## COMMANDS - -{{range .VisibleCategories}}{{if .Name}}{{.Name}}:{{end}} -||| -|---|---|{{range .VisibleCommands}} -| **{{join .Names ", "}}** | {{.Usage}} |{{end}} -{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` - -// CommandHelpTemplate contains the modified template for a command -var CommandHelpTemplate = `## NAME -**{{.HelpName}}** -- {{.Usage}} - -## USAGE - -{{if .UsageText}}{{.UsageText}}{{else}}**{{.HelpName}}**{{if .VisibleFlags}} _[options]_{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}_[arguments]_{{end}}{{end}}{{if .Category}} - -## CATEGORY - -{{.Category}}{{end}}{{if .Description}} - -## DESCRIPTION - -{{.Description}}{{end}}{{if .VisibleFlags}} - -## OPTIONS - -{{range .VisibleFlags}} -{{.}} -{{end}}{{end}} -` - -// FlagNamePrefixer converts a full flag name and its placeholder into the help -// message flag prefix. This is used by the default FlagStringer. -// -// This method clones urflave/cli functionality but adds a new line at the end. -func FlagNamePrefixer(fullName, placeholder string) string { - var prefixed string - parts := strings.Split(fullName, ",") - for i, name := range parts { - name = strings.Trim(name, " ") - prefixed += "**" + prefixFor(name) + name + "**" - - if placeholder != "" { - prefixed += "=" + placeholder - } - if i < len(parts)-1 { - prefixed += ", " - } - } - //return "* " + prefixed + "\n" - return prefixed + "\n: " -} - -func prefixFor(name string) (prefix string) { - if len(name) == 1 { - prefix = "-" - } else { - prefix = "--" - } - - return -} diff --git a/vendor/github.com/smallstep/nosql/postgresql/postgresql.go b/vendor/github.com/smallstep/nosql/postgresql/postgresql.go index 67716c5..4109f99 100644 --- a/vendor/github.com/smallstep/nosql/postgresql/postgresql.go +++ b/vendor/github.com/smallstep/nosql/postgresql/postgresql.go @@ -10,8 +10,8 @@ import ( "fmt" "strings" - "github.com/jackc/pgx/v5" - pgxstdlib "github.com/jackc/pgx/v5/stdlib" + "github.com/jackc/pgx/v4" + pgxstdlib "github.com/jackc/pgx/v4/stdlib" "github.com/pkg/errors" "github.com/smallstep/nosql/database" ) diff --git a/vendor/github.com/smallstep/pkcs7/.gitignore b/vendor/github.com/smallstep/pkcs7/.gitignore index 948aae2..daf913b 100644 --- a/vendor/github.com/smallstep/pkcs7/.gitignore +++ b/vendor/github.com/smallstep/pkcs7/.gitignore @@ -22,7 +22,3 @@ _testmain.go *.exe *.test *.prof - -# Development -.envrc -coverage.out
\ No newline at end of file diff --git a/vendor/github.com/smallstep/pkcs7/README.md b/vendor/github.com/smallstep/pkcs7/README.md index 9d94e65..a55d117 100644 --- a/vendor/github.com/smallstep/pkcs7/README.md +++ b/vendor/github.com/smallstep/pkcs7/README.md @@ -1,7 +1,7 @@ # pkcs7 -[](https://pkg.go.dev/github.com/smallstep/pkcs7) -[](https://github.com/smallstep/pkcs7/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush) +[](https://godoc.org/go.mozilla.org/pkcs7) +[](https://github.com/mozilla-services/pkcs7/actions/workflows/ci.yml?query=branch%3Amaster+event%3Apush) pkcs7 implements parsing and creating signed and enveloped messages. @@ -16,16 +16,18 @@ import ( "fmt" "os" - "github.com/smallstep/pkcs7" + "go.mozilla.org/pkcs7" ) func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateKey) (signed []byte, err error) { toBeSigned, err := NewSignedData(content) if err != nil { - return fmt.Errorf("Cannot initialize signed data: %w", err) + err = fmt.Errorf("Cannot initialize signed data: %s", err) + return } if err = toBeSigned.AddSigner(cert, privkey, SignerInfoConfig{}); err != nil { - return fmt.Errorf("Cannot add signer: %w", err) + err = fmt.Errorf("Cannot add signer: %s", err) + return } // Detach signature, omit if you want an embedded signature @@ -33,24 +35,28 @@ func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateK signed, err = toBeSigned.Finish() if err != nil { - return fmt.Errorf("Cannot finish signing data: %w", err) + err = fmt.Errorf("Cannot finish signing data: %s", err) + return } // Verify the signature pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed}) p7, err := pkcs7.Parse(signed) if err != nil { - return fmt.Errorf("Cannot parse our signed data: %w", err) + err = fmt.Errorf("Cannot parse our signed data: %s", err) + return } // since the signature was detached, reattach the content here p7.Content = content if bytes.Compare(content, p7.Content) != 0 { - return fmt.Errorf("Our content was not in the parsed data:\n\tExpected: %s\n\tActual: %s", content, p7.Content) + err = fmt.Errorf("Our content was not in the parsed data:\n\tExpected: %s\n\tActual: %s", content, p7.Content) + return } if err = p7.Verify(); err != nil { - return fmt.Errorf("Cannot verify our signed data: %w", err) + err = fmt.Errorf("Cannot verify our signed data: %s", err) + return } return signed, nil @@ -58,6 +64,6 @@ func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateK ``` -## Credits -This is a fork of [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) which, itself, was a fork of [fullsailor/pkcs7](https://github.com/fullsailor/pkcs7). +## Credits +This is a fork of [fullsailor/pkcs7](https://github.com/fullsailor/pkcs7) diff --git a/vendor/github.com/smallstep/pkcs7/ber.go b/vendor/github.com/smallstep/pkcs7/ber.go index 5233321..73da024 100644 --- a/vendor/github.com/smallstep/pkcs7/ber.go +++ b/vendor/github.com/smallstep/pkcs7/ber.go @@ -5,6 +5,8 @@ import ( "errors" ) +var encodeIndent = 0 + type asn1Object interface { EncodeTo(writer *bytes.Buffer) error } @@ -15,6 +17,8 @@ type asn1Structured struct { } func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { + //fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes) + encodeIndent++ inner := new(bytes.Buffer) for _, obj := range s.content { err := obj.EncodeTo(inner) @@ -22,6 +26,7 @@ func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { return err } } + encodeIndent-- out.Write(s.tagBytes) encodeLength(out, inner.Len()) out.Write(inner.Bytes()) @@ -42,8 +47,8 @@ func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error { if err = encodeLength(out, p.length); err != nil { return err } - // fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length) - // fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content)) + //fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length) + //fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content)) out.Write(p.content) return nil @@ -53,7 +58,7 @@ func ber2der(ber []byte) ([]byte, error) { if len(ber) == 0 { return nil, errors.New("ber2der: input ber is empty") } - // fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber)) + //fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber)) out := new(bytes.Buffer) obj, _, err := readObject(ber, 0) @@ -64,7 +69,7 @@ func ber2der(ber []byte) ([]byte, error) { // if offset < len(ber) { // return nil, fmt.Errorf("ber2der: Content longer than expected. Got %d, expected %d", offset, len(ber)) - // } + //} return out.Bytes(), nil } @@ -149,7 +154,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { } } // jvehent 20170227: this doesn't appear to be used anywhere... - // tag = tag*128 + ber[offset] - 0x80 + //tag = tag*128 + ber[offset] - 0x80 offset++ if offset > berLen { return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") @@ -199,7 +204,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { if length < 0 { return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length") } - // fmt.Printf("--> length : %d\n", length) + //fmt.Printf("--> length : %d\n", length) contentEnd := offset + length if contentEnd > len(ber) { return nil, 0, errors.New("ber2der: BER tag length is more than available data") @@ -254,7 +259,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) { } func isIndefiniteTermination(ber []byte, offset int) (bool, error) { - if len(ber)-offset < 2 { + if len(ber) - offset < 2 { return false, errors.New("ber2der: Invalid BER format") } @@ -262,5 +267,5 @@ func isIndefiniteTermination(ber []byte, offset int) (bool, error) { } func debugprint(format string, a ...interface{}) { - // fmt.Printf(format, a) + //fmt.Printf(format, a) } diff --git a/vendor/github.com/smallstep/pkcs7/encrypt.go b/vendor/github.com/smallstep/pkcs7/encrypt.go index a5c96e7..4c02e40 100644 --- a/vendor/github.com/smallstep/pkcs7/encrypt.go +++ b/vendor/github.com/smallstep/pkcs7/encrypt.go @@ -443,7 +443,8 @@ func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) { } func marshalEncryptedContent(content []byte) asn1.RawValue { - return asn1.RawValue{Bytes: content, Class: 2, IsCompound: false} + asn1Content, _ := asn1.Marshal(content) + return asn1.RawValue{Tag: 0, Class: 2, Bytes: asn1Content, IsCompound: true} } func encryptKey(key []byte, recipient *x509.Certificate, algorithm asn1.ObjectIdentifier, hash crypto.Hash) ([]byte, error) { diff --git a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/debug.go b/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/debug.go deleted file mode 100644 index 378cc26..0000000 --- a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/debug.go +++ /dev/null @@ -1,14 +0,0 @@ -package legacyx509 - -import "fmt" - -// legacyGodebugSetting is a type mimicking Go's internal godebug package -// settings, which are used to enable / disable certain functionalities at -// build time. -type legacyGodebugSetting int - -func (s legacyGodebugSetting) Value() string { - return fmt.Sprintf("%d", s) -} - -func (s legacyGodebugSetting) IncNonDefault() {} diff --git a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/doc.go b/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/doc.go deleted file mode 100644 index 7d1469b..0000000 --- a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/doc.go +++ /dev/null @@ -1,14 +0,0 @@ -/* -Package legacyx509 is a copy of certain parts of Go's crypto/x509 package. -It is based on Go 1.23, and has just the parts copied over required for -parsing X509 certificates. - -The primary reason this copy exists is to keep support for parsing PKCS7 -messages containing Simple Certificate Enrolment Protocol (SCEP) requests -from Windows devices. Go 1.23 made a change marking certificates with a -critical authority key identifier as invalid, which is mandated by RFC 5280, -but apparently Windows marks those specific certificates as such, resulting -in those SCEP requests failing from being parsed correctly. -*/ - -package legacyx509 diff --git a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/oid.go b/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/oid.go deleted file mode 100644 index 8268a07..0000000 --- a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/oid.go +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright 2023 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 legacyx509 - -import ( - "bytes" - "encoding/asn1" - "errors" - "math" - "math/big" - "math/bits" - "strconv" - "strings" -) - -var ( - errInvalidOID = errors.New("invalid oid") -) - -// An OID represents an ASN.1 OBJECT IDENTIFIER. -type OID struct { - der []byte -} - -// ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots. -func ParseOID(oid string) (OID, error) { - var o OID - return o, o.unmarshalOIDText(oid) -} - -func newOIDFromDER(der []byte) (OID, bool) { - if len(der) == 0 || der[len(der)-1]&0x80 != 0 { - return OID{}, false - } - - start := 0 - for i, v := range der { - // ITU-T X.690, section 8.19.2: - // The subidentifier shall be encoded in the fewest possible octets, - // that is, the leading octet of the subidentifier shall not have the value 0x80. - if i == start && v == 0x80 { - return OID{}, false - } - if v&0x80 == 0 { - start = i + 1 - } - } - - return OID{der}, true -} - -// OIDFromInts creates a new OID using ints, each integer is a separate component. -func OIDFromInts(oid []uint64) (OID, error) { - if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { - return OID{}, errInvalidOID - } - - length := base128IntLength(oid[0]*40 + oid[1]) - for _, v := range oid[2:] { - length += base128IntLength(v) - } - - der := make([]byte, 0, length) - der = appendBase128Int(der, oid[0]*40+oid[1]) - for _, v := range oid[2:] { - der = appendBase128Int(der, v) - } - return OID{der}, nil -} - -func base128IntLength(n uint64) int { - if n == 0 { - return 1 - } - return (bits.Len64(n) + 6) / 7 -} - -func appendBase128Int(dst []byte, n uint64) []byte { - for i := base128IntLength(n) - 1; i >= 0; i-- { - o := byte(n >> uint(i*7)) - o &= 0x7f - if i != 0 { - o |= 0x80 - } - dst = append(dst, o) - } - return dst -} - -func base128BigIntLength(n *big.Int) int { - if n.Cmp(big.NewInt(0)) == 0 { - return 1 - } - return (n.BitLen() + 6) / 7 -} - -func appendBase128BigInt(dst []byte, n *big.Int) []byte { - if n.Cmp(big.NewInt(0)) == 0 { - return append(dst, 0) - } - - for i := base128BigIntLength(n) - 1; i >= 0; i-- { - o := byte(big.NewInt(0).Rsh(n, uint(i)*7).Bits()[0]) - o &= 0x7f - if i != 0 { - o |= 0x80 - } - dst = append(dst, o) - } - return dst -} - -// AppendText implements [encoding.TextAppender] -func (o OID) AppendText(b []byte) ([]byte, error) { - return append(b, o.String()...), nil -} - -// MarshalText implements [encoding.TextMarshaler] -func (o OID) MarshalText() ([]byte, error) { - return o.AppendText(nil) -} - -// UnmarshalText implements [encoding.TextUnmarshaler] -func (o *OID) UnmarshalText(text []byte) error { - return o.unmarshalOIDText(string(text)) -} - -// cutString slices s around the first instance of sep, -// returning the text before and after sep. -// The found result reports whether sep appears in s. -// If sep does not appear in s, cut returns s, "", false. -func cutString(s, sep string) (before, after string, found bool) { - if i := strings.Index(s, sep); i >= 0 { - return s[:i], s[i+len(sep):], true - } - return s, "", false -} - -func (o *OID) unmarshalOIDText(oid string) error { - // (*big.Int).SetString allows +/- signs, but we don't want - // to allow them in the string representation of Object Identifier, so - // reject such encodings. - for _, c := range oid { - isDigit := c >= '0' && c <= '9' - if !isDigit && c != '.' { - return errInvalidOID - } - } - - var ( - firstNum string - secondNum string - ) - - var nextComponentExists bool - firstNum, oid, nextComponentExists = cutString(oid, ".") - if !nextComponentExists { - return errInvalidOID - } - secondNum, oid, nextComponentExists = cutString(oid, ".") - - var ( - first = big.NewInt(0) - second = big.NewInt(0) - ) - - if _, ok := first.SetString(firstNum, 10); !ok { - return errInvalidOID - } - if _, ok := second.SetString(secondNum, 10); !ok { - return errInvalidOID - } - - if first.Cmp(big.NewInt(2)) > 0 || (first.Cmp(big.NewInt(2)) < 0 && second.Cmp(big.NewInt(40)) >= 0) { - return errInvalidOID - } - - firstComponent := first.Mul(first, big.NewInt(40)) - firstComponent.Add(firstComponent, second) - - der := appendBase128BigInt(make([]byte, 0, 32), firstComponent) - - for nextComponentExists { - var strNum string - strNum, oid, nextComponentExists = cutString(oid, ".") - b, ok := big.NewInt(0).SetString(strNum, 10) - if !ok { - return errInvalidOID - } - der = appendBase128BigInt(der, b) - } - - o.der = der - return nil -} - -// AppendBinary implements [encoding.BinaryAppender] -func (o OID) AppendBinary(b []byte) ([]byte, error) { - return append(b, o.der...), nil -} - -// MarshalBinary implements [encoding.BinaryMarshaler] -func (o OID) MarshalBinary() ([]byte, error) { - return o.AppendBinary(nil) -} - -// cloneBytes returns a copy of b[:len(b)]. -// The result may have additional unused capacity. -// Clone(nil) returns nil. -func cloneBytes(b []byte) []byte { - if b == nil { - return nil - } - return append([]byte{}, b...) -} - -// UnmarshalBinary implements [encoding.BinaryUnmarshaler] -func (o *OID) UnmarshalBinary(b []byte) error { - oid, ok := newOIDFromDER(cloneBytes(b)) - if !ok { - return errInvalidOID - } - *o = oid - return nil -} - -// Equal returns true when oid and other represents the same Object Identifier. -func (oid OID) Equal(other OID) bool { - // There is only one possible DER encoding of - // each unique Object Identifier. - return bytes.Equal(oid.der, other.der) -} - -func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, failed bool) { - offset = initOffset - var ret64 int64 - for shifted := 0; offset < len(bytes); shifted++ { - // 5 * 7 bits per byte == 35 bits of data - // Thus the representation is either non-minimal or too large for an int32 - if shifted == 5 { - failed = true - return - } - ret64 <<= 7 - b := bytes[offset] - // integers should be minimally encoded, so the leading octet should - // never be 0x80 - if shifted == 0 && b == 0x80 { - failed = true - return - } - ret64 |= int64(b & 0x7f) - offset++ - if b&0x80 == 0 { - ret = int(ret64) - // Ensure that the returned value fits in an int on all platforms - if ret64 > math.MaxInt32 { - failed = true - } - return - } - } - failed = true - return -} - -// EqualASN1OID returns whether an OID equals an asn1.ObjectIdentifier. If -// asn1.ObjectIdentifier cannot represent the OID specified by oid, because -// a component of OID requires more than 31 bits, it returns false. -func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool { - if len(other) < 2 { - return false - } - v, offset, failed := parseBase128Int(oid.der, 0) - if failed { - // This should never happen, since we've already parsed the OID, - // but just in case. - return false - } - if v < 80 { - a, b := v/40, v%40 - if other[0] != a || other[1] != b { - return false - } - } else { - a, b := 2, v-80 - if other[0] != a || other[1] != b { - return false - } - } - - i := 2 - for ; offset < len(oid.der); i++ { - v, offset, failed = parseBase128Int(oid.der, offset) - if failed { - // Again, shouldn't happen, since we've already parsed - // the OID, but better safe than sorry. - return false - } - if i >= len(other) || v != other[i] { - return false - } - } - - return i == len(other) -} - -// Strings returns the string representation of the Object Identifier. -func (oid OID) String() string { - var b strings.Builder - b.Grow(32) - const ( - valSize = 64 // size in bits of val. - bitsPerByte = 7 - maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1 - ) - var ( - start = 0 - val = uint64(0) - numBuf = make([]byte, 0, 21) - bigVal *big.Int - overflow bool - ) - for i, v := range oid.der { - curVal := v & 0x7F - valEnd := v&0x80 == 0 - if valEnd { - if start != 0 { - b.WriteByte('.') - } - } - if !overflow && val > maxValSafeShift { - if bigVal == nil { - bigVal = new(big.Int) - } - bigVal = bigVal.SetUint64(val) - overflow = true - } - if overflow { - bigVal = bigVal.Lsh(bigVal, bitsPerByte).Or(bigVal, big.NewInt(int64(curVal))) - if valEnd { - if start == 0 { - b.WriteString("2.") - bigVal = bigVal.Sub(bigVal, big.NewInt(80)) - } - numBuf = bigVal.Append(numBuf, 10) - b.Write(numBuf) - numBuf = numBuf[:0] - val = 0 - start = i + 1 - overflow = false - } - continue - } - val <<= bitsPerByte - val |= uint64(curVal) - if valEnd { - if start == 0 { - if val < 80 { - b.Write(strconv.AppendUint(numBuf, val/40, 10)) - b.WriteByte('.') - b.Write(strconv.AppendUint(numBuf, val%40, 10)) - } else { - b.WriteString("2.") - b.Write(strconv.AppendUint(numBuf, val-80, 10)) - } - } else { - b.Write(strconv.AppendUint(numBuf, val, 10)) - } - val = 0 - start = i + 1 - } - } - return b.String() -} diff --git a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/parser.go b/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/parser.go deleted file mode 100644 index ec57e79..0000000 --- a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/parser.go +++ /dev/null @@ -1,1027 +0,0 @@ -// Copyright 2021 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 legacyx509 - -import ( - "bytes" - "crypto/dsa" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/elliptic" - "crypto/rsa" - "crypto/x509/pkix" - "encoding/asn1" - "errors" - "fmt" - "math/big" - "net" - "net/url" - "strconv" - "strings" - "time" - "unicode/utf16" - "unicode/utf8" - - "golang.org/x/crypto/cryptobyte" - cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" - - stdx509 "crypto/x509" -) - -// ParseCertificates parses one or more certificates from the given ASN.1 DER -// data. The certificates must be concatenated with no intermediate padding. -func ParseCertificates(der []byte) ([]*stdx509.Certificate, error) { - var certs []*stdx509.Certificate - for len(der) > 0 { - cert, err := parseCertificate(der) - if err != nil { - return nil, err - } - certs = append(certs, cert) - der = der[len(cert.Raw):] - } - return certs, nil -} - -// isPrintable reports whether the given b is in the ASN.1 PrintableString set. -// This is a simplified version of encoding/asn1.isPrintable. -func isPrintable(b byte) bool { - return 'a' <= b && b <= 'z' || - 'A' <= b && b <= 'Z' || - '0' <= b && b <= '9' || - '\'' <= b && b <= ')' || - '+' <= b && b <= '/' || - b == ' ' || - b == ':' || - b == '=' || - b == '?' || - // This is technically not allowed in a PrintableString. - // However, x509 certificates with wildcard strings don't - // always use the correct string type so we permit it. - b == '*' || - // This is not technically allowed either. However, not - // only is it relatively common, but there are also a - // handful of CA certificates that contain it. At least - // one of which will not expire until 2027. - b == '&' -} - -// parseASN1String parses the ASN.1 string types T61String, PrintableString, -// UTF8String, BMPString, IA5String, and NumericString. This is mostly copied -// from the respective encoding/asn1.parse... methods, rather than just -// increasing the API surface of that package. -func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) { - switch tag { - case cryptobyte_asn1.T61String: - return string(value), nil - case cryptobyte_asn1.PrintableString: - for _, b := range value { - if !isPrintable(b) { - return "", errors.New("invalid PrintableString") - } - } - return string(value), nil - case cryptobyte_asn1.UTF8String: - if !utf8.Valid(value) { - return "", errors.New("invalid UTF-8 string") - } - return string(value), nil - case cryptobyte_asn1.Tag(asn1.TagBMPString): - if len(value)%2 != 0 { - return "", errors.New("invalid BMPString") - } - - // Strip terminator if present. - if l := len(value); l >= 2 && value[l-1] == 0 && value[l-2] == 0 { - value = value[:l-2] - } - - s := make([]uint16, 0, len(value)/2) - for len(value) > 0 { - s = append(s, uint16(value[0])<<8+uint16(value[1])) - value = value[2:] - } - - return string(utf16.Decode(s)), nil - case cryptobyte_asn1.IA5String: - s := string(value) - if isIA5String(s) != nil { - return "", errors.New("invalid IA5String") - } - return s, nil - case cryptobyte_asn1.Tag(asn1.TagNumericString): - for _, b := range value { - if !('0' <= b && b <= '9' || b == ' ') { - return "", errors.New("invalid NumericString") - } - } - return string(value), nil - } - return "", fmt.Errorf("unsupported string type: %v", tag) -} - -// parseName parses a DER encoded Name as defined in RFC 5280. We may -// want to export this function in the future for use in crypto/tls. -func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { - if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: invalid RDNSequence") - } - - var rdnSeq pkix.RDNSequence - for !raw.Empty() { - var rdnSet pkix.RelativeDistinguishedNameSET - var set cryptobyte.String - if !raw.ReadASN1(&set, cryptobyte_asn1.SET) { - return nil, errors.New("x509: invalid RDNSequence") - } - for !set.Empty() { - var atav cryptobyte.String - if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: invalid RDNSequence: invalid attribute") - } - var attr pkix.AttributeTypeAndValue - if !atav.ReadASN1ObjectIdentifier(&attr.Type) { - return nil, errors.New("x509: invalid RDNSequence: invalid attribute type") - } - var rawValue cryptobyte.String - var valueTag cryptobyte_asn1.Tag - if !atav.ReadAnyASN1(&rawValue, &valueTag) { - return nil, errors.New("x509: invalid RDNSequence: invalid attribute value") - } - var err error - attr.Value, err = parseASN1String(valueTag, rawValue) - if err != nil { - return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", err) - } - rdnSet = append(rdnSet, attr) - } - - rdnSeq = append(rdnSeq, rdnSet) - } - - return &rdnSeq, nil -} - -func parseAI(der cryptobyte.String) (pkix.AlgorithmIdentifier, error) { - ai := pkix.AlgorithmIdentifier{} - if !der.ReadASN1ObjectIdentifier(&ai.Algorithm) { - return ai, errors.New("x509: malformed OID") - } - if der.Empty() { - return ai, nil - } - var params cryptobyte.String - var tag cryptobyte_asn1.Tag - if !der.ReadAnyASN1Element(¶ms, &tag) { - return ai, errors.New("x509: malformed parameters") - } - ai.Parameters.Tag = int(tag) - ai.Parameters.FullBytes = params - return ai, nil -} - -func parseTime(der *cryptobyte.String) (time.Time, error) { - var t time.Time - switch { - case der.PeekASN1Tag(cryptobyte_asn1.UTCTime): - if !der.ReadASN1UTCTime(&t) { - return t, errors.New("x509: malformed UTCTime") - } - case der.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime): - if !der.ReadASN1GeneralizedTime(&t) { - return t, errors.New("x509: malformed GeneralizedTime") - } - default: - return t, errors.New("x509: unsupported time format") - } - return t, nil -} - -func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) { - notBefore, err := parseTime(&der) - if err != nil { - return time.Time{}, time.Time{}, err - } - notAfter, err := parseTime(&der) - if err != nil { - return time.Time{}, time.Time{}, err - } - - return notBefore, notAfter, nil -} - -func parseExtension(der cryptobyte.String) (pkix.Extension, error) { - var ext pkix.Extension - if !der.ReadASN1ObjectIdentifier(&ext.Id) { - return ext, errors.New("x509: malformed extension OID field") - } - if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { - if !der.ReadASN1Boolean(&ext.Critical) { - return ext, errors.New("x509: malformed extension critical field") - } - } - var val cryptobyte.String - if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) { - return ext, errors.New("x509: malformed extension value field") - } - ext.Value = val - return ext, nil -} - -func parsePublicKey(keyData *publicKeyInfo) (interface{}, error) { - oid := keyData.Algorithm.Algorithm - params := keyData.Algorithm.Parameters - der := cryptobyte.String(keyData.PublicKey.RightAlign()) - switch { - case oid.Equal(oidPublicKeyRSA): - // RSA public keys must have a NULL in the parameters. - // See RFC 3279, Section 2.3.1. - if !bytes.Equal(params.FullBytes, asn1.NullBytes) { - return nil, errors.New("x509: RSA key missing NULL parameters") - } - - p := &pkcs1PublicKey{N: new(big.Int)} - if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: invalid RSA public key") - } - if !der.ReadASN1Integer(p.N) { - return nil, errors.New("x509: invalid RSA modulus") - } - if !der.ReadASN1Integer(&p.E) { - return nil, errors.New("x509: invalid RSA public exponent") - } - - if p.N.Sign() <= 0 { - return nil, errors.New("x509: RSA modulus is not a positive number") - } - if p.E <= 0 { - return nil, errors.New("x509: RSA public exponent is not a positive number") - } - - pub := &rsa.PublicKey{ - E: p.E, - N: p.N, - } - return pub, nil - case oid.Equal(oidPublicKeyECDSA): - paramsDer := cryptobyte.String(params.FullBytes) - namedCurveOID := new(asn1.ObjectIdentifier) - if !paramsDer.ReadASN1ObjectIdentifier(namedCurveOID) { - return nil, errors.New("x509: invalid ECDSA parameters") - } - namedCurve := namedCurveFromOID(*namedCurveOID) - if namedCurve == nil { - return nil, errors.New("x509: unsupported elliptic curve") - } - x, y := elliptic.Unmarshal(namedCurve, der) - if x == nil { - return nil, errors.New("x509: failed to unmarshal elliptic curve point") - } - pub := &ecdsa.PublicKey{ - Curve: namedCurve, - X: x, - Y: y, - } - return pub, nil - case oid.Equal(oidPublicKeyEd25519): - // RFC 8410, Section 3 - // > For all of the OIDs, the parameters MUST be absent. - if len(params.FullBytes) != 0 { - return nil, errors.New("x509: Ed25519 key encoded with illegal parameters") - } - if len(der) != ed25519.PublicKeySize { - return nil, errors.New("x509: wrong Ed25519 public key size") - } - return ed25519.PublicKey(der), nil - // case oid.Equal(oidPublicKeyX25519): - // // RFC 8410, Section 3 - // // > For all of the OIDs, the parameters MUST be absent. - // if len(params.FullBytes) != 0 { - // return nil, errors.New("x509: X25519 key encoded with illegal parameters") - // } - // return ecdh.X25519().NewPublicKey(der) - case oid.Equal(oidPublicKeyDSA): - y := new(big.Int) - if !der.ReadASN1Integer(y) { - return nil, errors.New("x509: invalid DSA public key") - } - pub := &dsa.PublicKey{ - Y: y, - Parameters: dsa.Parameters{ - P: new(big.Int), - Q: new(big.Int), - G: new(big.Int), - }, - } - paramsDer := cryptobyte.String(params.FullBytes) - if !paramsDer.ReadASN1(¶msDer, cryptobyte_asn1.SEQUENCE) || - !paramsDer.ReadASN1Integer(pub.Parameters.P) || - !paramsDer.ReadASN1Integer(pub.Parameters.Q) || - !paramsDer.ReadASN1Integer(pub.Parameters.G) { - return nil, errors.New("x509: invalid DSA parameters") - } - if pub.Y.Sign() <= 0 || pub.Parameters.P.Sign() <= 0 || - pub.Parameters.Q.Sign() <= 0 || pub.Parameters.G.Sign() <= 0 { - return nil, errors.New("x509: zero or negative DSA parameter") - } - return pub, nil - default: - return nil, errors.New("x509: unknown public key algorithm") - } -} - -func parseKeyUsageExtension(der cryptobyte.String) (stdx509.KeyUsage, error) { - var usageBits asn1.BitString - if !der.ReadASN1BitString(&usageBits) { - return 0, errors.New("x509: invalid key usage") - } - - var usage int - for i := 0; i < 9; i++ { - if usageBits.At(i) != 0 { - usage |= 1 << uint(i) - } - } - return stdx509.KeyUsage(usage), nil -} - -func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) { - var isCA bool - if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { - return false, 0, errors.New("x509: invalid basic constraints") - } - if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { - if !der.ReadASN1Boolean(&isCA) { - return false, 0, errors.New("x509: invalid basic constraints") - } - } - maxPathLen := -1 - if der.PeekASN1Tag(cryptobyte_asn1.INTEGER) { - if !der.ReadASN1Integer(&maxPathLen) { - return false, 0, errors.New("x509: invalid basic constraints") - } - } - - // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) - return isCA, maxPathLen, nil -} - -func forEachSAN(der cryptobyte.String, callback func(tag int, data []byte) error) error { - if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { - return errors.New("x509: invalid subject alternative names") - } - for !der.Empty() { - var san cryptobyte.String - var tag cryptobyte_asn1.Tag - if !der.ReadAnyASN1(&san, &tag) { - return errors.New("x509: invalid subject alternative name") - } - if err := callback(int(tag^0x80), san); err != nil { - return err - } - } - - return nil -} - -func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { - err = forEachSAN(der, func(tag int, data []byte) error { - switch tag { - case nameTypeEmail: - email := string(data) - if err := isIA5String(email); err != nil { - return errors.New("x509: SAN rfc822Name is malformed") - } - emailAddresses = append(emailAddresses, email) - case nameTypeDNS: - name := string(data) - if err := isIA5String(name); err != nil { - return errors.New("x509: SAN dNSName is malformed") - } - dnsNames = append(dnsNames, string(name)) - case nameTypeURI: - uriStr := string(data) - if err := isIA5String(uriStr); err != nil { - return errors.New("x509: SAN uniformResourceIdentifier is malformed") - } - uri, err := url.Parse(uriStr) - if err != nil { - return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err) - } - if len(uri.Host) > 0 { - if _, ok := domainToReverseLabels(uri.Host); !ok { - return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr) - } - } - uris = append(uris, uri) - case nameTypeIP: - switch len(data) { - case net.IPv4len, net.IPv6len: - ipAddresses = append(ipAddresses, data) - default: - return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data))) - } - } - - return nil - }) - - return -} - -func parseAuthorityKeyIdentifier(e pkix.Extension) ([]byte, error) { - // RFC 5280, Section 4.2.1.1 - // if e.Critical { - // // Conforming CAs MUST mark this extension as non-critical - // return nil, errors.New("x509: authority key identifier incorrectly marked critical") - // } - val := cryptobyte.String(e.Value) - var akid cryptobyte.String - if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: invalid authority key identifier") - } - if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { - if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { - return nil, errors.New("x509: invalid authority key identifier") - } - return akid, nil - } - return nil, nil -} - -func parseExtKeyUsageExtension(der cryptobyte.String) ([]stdx509.ExtKeyUsage, []asn1.ObjectIdentifier, error) { - var extKeyUsages []stdx509.ExtKeyUsage - var unknownUsages []asn1.ObjectIdentifier - if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { - return nil, nil, errors.New("x509: invalid extended key usages") - } - for !der.Empty() { - var eku asn1.ObjectIdentifier - if !der.ReadASN1ObjectIdentifier(&eku) { - return nil, nil, errors.New("x509: invalid extended key usages") - } - if extKeyUsage, ok := extKeyUsageFromOID(eku); ok { - extKeyUsages = append(extKeyUsages, stdx509.ExtKeyUsage(extKeyUsage)) - } else { - unknownUsages = append(unknownUsages, eku) - } - } - return extKeyUsages, unknownUsages, nil -} - -// func parseCertificatePoliciesExtension(der cryptobyte.String) ([]OID, error) { -// var oids []OID -// if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { -// return nil, errors.New("x509: invalid certificate policies") -// } -// for !der.Empty() { -// var cp cryptobyte.String -// var OIDBytes cryptobyte.String -// if !der.ReadASN1(&cp, cryptobyte_asn1.SEQUENCE) || !cp.ReadASN1(&OIDBytes, cryptobyte_asn1.OBJECT_IDENTIFIER) { -// return nil, errors.New("x509: invalid certificate policies") -// } -// oid, ok := newOIDFromDER(OIDBytes) -// if !ok { -// return nil, errors.New("x509: invalid certificate policies") -// } -// oids = append(oids, oid) -// } -// return oids, nil -// } - -// isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. -func isValidIPMask(mask []byte) bool { - seenZero := false - - for _, b := range mask { - if seenZero { - if b != 0 { - return false - } - - continue - } - - switch b { - case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: - seenZero = true - case 0xff: - default: - return false - } - } - - return true -} - -func parseNameConstraintsExtension(out *stdx509.Certificate, e pkix.Extension) (unhandled bool, err error) { - // RFC 5280, 4.2.1.10 - - // NameConstraints ::= SEQUENCE { - // permittedSubtrees [0] GeneralSubtrees OPTIONAL, - // excludedSubtrees [1] GeneralSubtrees OPTIONAL } - // - // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree - // - // GeneralSubtree ::= SEQUENCE { - // base GeneralName, - // minimum [0] BaseDistance DEFAULT 0, - // maximum [1] BaseDistance OPTIONAL } - // - // BaseDistance ::= INTEGER (0..MAX) - - outer := cryptobyte.String(e.Value) - var toplevel, permitted, excluded cryptobyte.String - var havePermitted, haveExcluded bool - if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || - !outer.Empty() || - !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || - !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || - !toplevel.Empty() { - return false, errors.New("x509: invalid NameConstraints extension") - } - - if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { - // From RFC 5280, Section 4.2.1.10: - // “either the permittedSubtrees field - // or the excludedSubtrees MUST be - // present” - return false, errors.New("x509: empty name constraints extension") - } - - getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { - for !subtrees.Empty() { - var seq, value cryptobyte.String - var tag cryptobyte_asn1.Tag - if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || - !seq.ReadAnyASN1(&value, &tag) { - return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") - } - - var ( - dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() - emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() - ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() - uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() - ) - - switch tag { - case dnsTag: - domain := string(value) - if err := isIA5String(domain); err != nil { - return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) - } - - trimmedDomain := domain - if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { - // constraints can have a leading - // period to exclude the domain - // itself, but that's not valid in a - // normal domain name. - trimmedDomain = trimmedDomain[1:] - } - if _, ok := domainToReverseLabels(trimmedDomain); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) - } - dnsNames = append(dnsNames, domain) - - case ipTag: - l := len(value) - var ip, mask []byte - - switch l { - case 8: - ip = value[:4] - mask = value[4:] - - case 32: - ip = value[:16] - mask = value[16:] - - default: - return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) - } - - if !isValidIPMask(mask) { - return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) - } - - ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) - - case emailTag: - constraint := string(value) - if err := isIA5String(constraint); err != nil { - return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) - } - - // If the constraint contains an @ then - // it specifies an exact mailbox name. - if strings.Contains(constraint, "@") { - if _, ok := parseRFC2821Mailbox(constraint); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) - } - } else { - // Otherwise it's a domain name. - domain := constraint - if len(domain) > 0 && domain[0] == '.' { - domain = domain[1:] - } - if _, ok := domainToReverseLabels(domain); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) - } - } - emails = append(emails, constraint) - - case uriTag: - domain := string(value) - if err := isIA5String(domain); err != nil { - return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) - } - - if net.ParseIP(domain) != nil { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) - } - - trimmedDomain := domain - if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { - // constraints can have a leading - // period to exclude the domain itself, - // but that's not valid in a normal - // domain name. - trimmedDomain = trimmedDomain[1:] - } - if _, ok := domainToReverseLabels(trimmedDomain); !ok { - return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) - } - uriDomains = append(uriDomains, domain) - - default: - unhandled = true - } - } - - return dnsNames, ips, emails, uriDomains, nil - } - - if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { - return false, err - } - if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { - return false, err - } - out.PermittedDNSDomainsCritical = e.Critical - - return unhandled, nil -} - -func processExtensions(out *stdx509.Certificate) error { - var err error - for _, e := range out.Extensions { - unhandled := false - - if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { - switch e.Id[3] { - case 15: - out.KeyUsage, err = parseKeyUsageExtension(e.Value) - if err != nil { - return err - } - case 19: - out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value) - if err != nil { - return err - } - out.BasicConstraintsValid = true - out.MaxPathLenZero = out.MaxPathLen == 0 - case 17: - out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value) - if err != nil { - return err - } - - if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { - // If we didn't parse anything then we do the critical check, below. - unhandled = true - } - - case 30: - unhandled, err = parseNameConstraintsExtension(out, e) - if err != nil { - return err - } - - case 31: - // RFC 5280, 4.2.1.13 - - // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint - // - // DistributionPoint ::= SEQUENCE { - // distributionPoint [0] DistributionPointName OPTIONAL, - // reasons [1] ReasonFlags OPTIONAL, - // cRLIssuer [2] GeneralNames OPTIONAL } - // - // DistributionPointName ::= CHOICE { - // fullName [0] GeneralNames, - // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } - val := cryptobyte.String(e.Value) - if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { - return errors.New("x509: invalid CRL distribution points") - } - for !val.Empty() { - var dpDER cryptobyte.String - if !val.ReadASN1(&dpDER, cryptobyte_asn1.SEQUENCE) { - return errors.New("x509: invalid CRL distribution point") - } - var dpNameDER cryptobyte.String - var dpNamePresent bool - if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { - return errors.New("x509: invalid CRL distribution point") - } - if !dpNamePresent { - continue - } - if !dpNameDER.ReadASN1(&dpNameDER, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { - return errors.New("x509: invalid CRL distribution point") - } - for !dpNameDER.Empty() { - if !dpNameDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { - break - } - var uri cryptobyte.String - if !dpNameDER.ReadASN1(&uri, cryptobyte_asn1.Tag(6).ContextSpecific()) { - return errors.New("x509: invalid CRL distribution point") - } - out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(uri)) - } - } - - case 35: - out.AuthorityKeyId, err = parseAuthorityKeyIdentifier(e) - if err != nil { - return err - } - case 37: - out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value) - if err != nil { - return err - } - case 14: - // RFC 5280, 4.2.1.2 - if e.Critical { - // Conforming CAs MUST mark this extension as non-critical - return errors.New("x509: subject key identifier incorrectly marked critical") - } - val := cryptobyte.String(e.Value) - var skid cryptobyte.String - if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) { - return errors.New("x509: invalid subject key identifier") - } - out.SubjectKeyId = skid - // case 32: - // out.Policies, err = parseCertificatePoliciesExtension(e.Value) - // if err != nil { - // return err - // } - // out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, 0, len(out.Policies)) - // for _, oid := range out.Policies { - // if oid, ok := oid.toASN1OID(); ok { - // out.PolicyIdentifiers = append(out.PolicyIdentifiers, oid) - // } - // } - default: - // Unknown extensions are recorded if critical. - unhandled = true - } - } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { - // RFC 5280 4.2.2.1: Authority Information Access - if e.Critical { - // Conforming CAs MUST mark this extension as non-critical - return errors.New("x509: authority info access incorrectly marked critical") - } - val := cryptobyte.String(e.Value) - if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { - return errors.New("x509: invalid authority info access") - } - for !val.Empty() { - var aiaDER cryptobyte.String - if !val.ReadASN1(&aiaDER, cryptobyte_asn1.SEQUENCE) { - return errors.New("x509: invalid authority info access") - } - var method asn1.ObjectIdentifier - if !aiaDER.ReadASN1ObjectIdentifier(&method) { - return errors.New("x509: invalid authority info access") - } - if !aiaDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { - continue - } - if !aiaDER.ReadASN1(&aiaDER, cryptobyte_asn1.Tag(6).ContextSpecific()) { - return errors.New("x509: invalid authority info access") - } - switch { - case method.Equal(oidAuthorityInfoAccessOcsp): - out.OCSPServer = append(out.OCSPServer, string(aiaDER)) - case method.Equal(oidAuthorityInfoAccessIssuers): - out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(aiaDER)) - } - } - } else { - // Unknown extensions are recorded if critical. - unhandled = true - } - - if e.Critical && unhandled { - out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) - } - } - - return nil -} - -var x509negativeserial = legacyGodebugSetting(0) // replaces godebug.New("x509negativeserial") - -func parseCertificate(der []byte) (*stdx509.Certificate, error) { - cert := &stdx509.Certificate{} - - input := cryptobyte.String(der) - // we read the SEQUENCE including length and tag bytes so that - // we can populate Certificate.Raw, before unwrapping the - // SEQUENCE so it can be operated on - if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed certificate") - } - cert.Raw = input - if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed certificate") - } - - var tbs cryptobyte.String - // do the same trick again as above to extract the raw - // bytes for Certificate.RawTBSCertificate - if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed tbs certificate") - } - cert.RawTBSCertificate = tbs - if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed tbs certificate") - } - - if !tbs.ReadOptionalASN1Integer(&cert.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) { - return nil, errors.New("x509: malformed version") - } - if cert.Version < 0 { - return nil, errors.New("x509: malformed version") - } - // for backwards compat reasons Version is one-indexed, - // rather than zero-indexed as defined in 5280 - cert.Version++ - if cert.Version > 3 { - return nil, errors.New("x509: invalid version") - } - - serial := new(big.Int) - if !tbs.ReadASN1Integer(serial) { - return nil, errors.New("x509: malformed serial number") - } - if serial.Sign() == -1 { - if x509negativeserial.Value() != "1" { - return nil, errors.New("x509: negative serial number") - } else { - x509negativeserial.IncNonDefault() - } - } - cert.SerialNumber = serial - - var sigAISeq cryptobyte.String - if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed signature algorithm identifier") - } - // Before parsing the inner algorithm identifier, extract - // the outer algorithm identifier and make sure that they - // match. - var outerSigAISeq cryptobyte.String - if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed algorithm identifier") - } - if !bytes.Equal(outerSigAISeq, sigAISeq) { - return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") - } - sigAI, err := parseAI(sigAISeq) - if err != nil { - return nil, err - } - cert.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) - - var issuerSeq cryptobyte.String - if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed issuer") - } - cert.RawIssuer = issuerSeq - issuerRDNs, err := parseName(issuerSeq) - if err != nil { - return nil, err - } - cert.Issuer.FillFromRDNSequence(issuerRDNs) - - var validity cryptobyte.String - if !tbs.ReadASN1(&validity, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed validity") - } - cert.NotBefore, cert.NotAfter, err = parseValidity(validity) - if err != nil { - return nil, err - } - - var subjectSeq cryptobyte.String - if !tbs.ReadASN1Element(&subjectSeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed issuer") - } - cert.RawSubject = subjectSeq - subjectRDNs, err := parseName(subjectSeq) - if err != nil { - return nil, err - } - cert.Subject.FillFromRDNSequence(subjectRDNs) - - var spki cryptobyte.String - if !tbs.ReadASN1Element(&spki, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed spki") - } - cert.RawSubjectPublicKeyInfo = spki - if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed spki") - } - var pkAISeq cryptobyte.String - if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed public key algorithm identifier") - } - pkAI, err := parseAI(pkAISeq) - if err != nil { - return nil, err - } - cert.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(pkAI.Algorithm) - var spk asn1.BitString - if !spki.ReadASN1BitString(&spk) { - return nil, errors.New("x509: malformed subjectPublicKey") - } - if cert.PublicKeyAlgorithm != stdx509.UnknownPublicKeyAlgorithm { - cert.PublicKey, err = parsePublicKey(&publicKeyInfo{ - Algorithm: pkAI, - PublicKey: spk, - }) - if err != nil { - return nil, err - } - } - - if cert.Version > 1 { - if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) { - return nil, errors.New("x509: malformed issuerUniqueID") - } - if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) { - return nil, errors.New("x509: malformed subjectUniqueID") - } - if cert.Version == 3 { - var extensions cryptobyte.String - var present bool - if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) { - return nil, errors.New("x509: malformed extensions") - } - if present { - seenExts := make(map[string]bool) - if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed extensions") - } - for !extensions.Empty() { - var extension cryptobyte.String - if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { - return nil, errors.New("x509: malformed extension") - } - ext, err := parseExtension(extension) - if err != nil { - return nil, err - } - oidStr := ext.Id.String() - if seenExts[oidStr] { - return nil, fmt.Errorf("x509: certificate contains duplicate extension with OID %q", oidStr) - } - seenExts[oidStr] = true - cert.Extensions = append(cert.Extensions, ext) - } - err = processExtensions(cert) - if err != nil { - return nil, err - } - } - } - } - - var signature asn1.BitString - if !input.ReadASN1BitString(&signature) { - return nil, errors.New("x509: malformed signature") - } - cert.Signature = signature.RightAlign() - - return cert, nil -} diff --git a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/pkcs1.go b/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/pkcs1.go deleted file mode 100644 index da3c38a..0000000 --- a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/pkcs1.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package legacyx509 - -import ( - "math/big" -) - -// pkcs1PublicKey reflects the ASN.1 structure of a PKCS #1 public key. -type pkcs1PublicKey struct { - N *big.Int - E int -} diff --git a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/verify.go b/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/verify.go deleted file mode 100644 index 901e3ba..0000000 --- a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/verify.go +++ /dev/null @@ -1,193 +0,0 @@ -package legacyx509 - -import ( - "bytes" - "strings" -) - -// rfc2821Mailbox represents a “mailbox” (which is an email address to most -// people) by breaking it into the “local” (i.e. before the '@') and “domain” -// parts. -type rfc2821Mailbox struct { - local, domain string -} - -// parseRFC2821Mailbox parses an email address into local and domain parts, -// based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280, -// Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The -// format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”. -func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) { - if len(in) == 0 { - return mailbox, false - } - - localPartBytes := make([]byte, 0, len(in)/2) - - if in[0] == '"' { - // Quoted-string = DQUOTE *qcontent DQUOTE - // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 - // qcontent = qtext / quoted-pair - // qtext = non-whitespace-control / - // %d33 / %d35-91 / %d93-126 - // quoted-pair = ("\" text) / obs-qp - // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text - // - // (Names beginning with “obs-” are the obsolete syntax from RFC 2822, - // Section 4. Since it has been 16 years, we no longer accept that.) - in = in[1:] - QuotedString: - for { - if len(in) == 0 { - return mailbox, false - } - c := in[0] - in = in[1:] - - switch { - case c == '"': - break QuotedString - - case c == '\\': - // quoted-pair - if len(in) == 0 { - return mailbox, false - } - if in[0] == 11 || - in[0] == 12 || - (1 <= in[0] && in[0] <= 9) || - (14 <= in[0] && in[0] <= 127) { - localPartBytes = append(localPartBytes, in[0]) - in = in[1:] - } else { - return mailbox, false - } - - case c == 11 || - c == 12 || - // Space (char 32) is not allowed based on the - // BNF, but RFC 3696 gives an example that - // assumes that it is. Several “verified” - // errata continue to argue about this point. - // We choose to accept it. - c == 32 || - c == 33 || - c == 127 || - (1 <= c && c <= 8) || - (14 <= c && c <= 31) || - (35 <= c && c <= 91) || - (93 <= c && c <= 126): - // qtext - localPartBytes = append(localPartBytes, c) - - default: - return mailbox, false - } - } - } else { - // Atom ("." Atom)* - NextChar: - for len(in) > 0 { - // atext from RFC 2822, Section 3.2.4 - c := in[0] - - switch { - case c == '\\': - // Examples given in RFC 3696 suggest that - // escaped characters can appear outside of a - // quoted string. Several “verified” errata - // continue to argue the point. We choose to - // accept it. - in = in[1:] - if len(in) == 0 { - return mailbox, false - } - fallthrough - - case ('0' <= c && c <= '9') || - ('a' <= c && c <= 'z') || - ('A' <= c && c <= 'Z') || - c == '!' || c == '#' || c == '$' || c == '%' || - c == '&' || c == '\'' || c == '*' || c == '+' || - c == '-' || c == '/' || c == '=' || c == '?' || - c == '^' || c == '_' || c == '`' || c == '{' || - c == '|' || c == '}' || c == '~' || c == '.': - localPartBytes = append(localPartBytes, in[0]) - in = in[1:] - - default: - break NextChar - } - } - - if len(localPartBytes) == 0 { - return mailbox, false - } - - // From RFC 3696, Section 3: - // “period (".") may also appear, but may not be used to start - // or end the local part, nor may two or more consecutive - // periods appear.” - twoDots := []byte{'.', '.'} - if localPartBytes[0] == '.' || - localPartBytes[len(localPartBytes)-1] == '.' || - bytes.Contains(localPartBytes, twoDots) { - return mailbox, false - } - } - - if len(in) == 0 || in[0] != '@' { - return mailbox, false - } - in = in[1:] - - // The RFC species a format for domains, but that's known to be - // violated in practice so we accept that anything after an '@' is the - // domain part. - if _, ok := domainToReverseLabels(in); !ok { - return mailbox, false - } - - mailbox.local = string(localPartBytes) - mailbox.domain = in - return mailbox, true -} - -// domainToReverseLabels converts a textual domain name like foo.example.com to -// the list of labels in reverse order, e.g. ["com", "example", "foo"]. -func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { - for len(domain) > 0 { - if i := strings.LastIndexByte(domain, '.'); i == -1 { - reverseLabels = append(reverseLabels, domain) - domain = "" - } else { - reverseLabels = append(reverseLabels, domain[i+1:]) - domain = domain[:i] - if i == 0 { // domain == "" - // domain is prefixed with an empty label, append an empty - // string to reverseLabels to indicate this. - reverseLabels = append(reverseLabels, "") - } - } - } - - if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 { - // An empty label at the end indicates an absolute value. - return nil, false - } - - for _, label := range reverseLabels { - if len(label) == 0 { - // Empty labels are otherwise invalid. - return nil, false - } - - for _, c := range label { - if c < 33 || c > 126 { - // Invalid character. - return nil, false - } - } - } - - return reverseLabels, true -} diff --git a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/x509.go b/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/x509.go deleted file mode 100644 index a4500bf..0000000 --- a/vendor/github.com/smallstep/pkcs7/internal/legacy/x509/x509.go +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2009 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 x509 implements a subset of the X.509 standard. -// -// It allows parsing and generating certificates, certificate signing -// requests, certificate revocation lists, and encoded public and private keys. -// It provides a certificate verifier, complete with a chain builder. -// -// The package targets the X.509 technical profile defined by the IETF (RFC -// 2459/3280/5280), and as further restricted by the CA/Browser Forum Baseline -// Requirements. There is minimal support for features outside of these -// profiles, as the primary goal of the package is to provide compatibility -// with the publicly trusted TLS certificate ecosystem and its policies and -// constraints. -// -// On macOS and Windows, certificate verification is handled by system APIs, but -// the package aims to apply consistent validation rules across operating -// systems. -package legacyx509 - -import ( - "bytes" - "crypto" - "crypto/elliptic" - stdx509 "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "fmt" - "strconv" - "unicode" - - // Explicitly import these for their crypto.RegisterHash init side-effects. - // Keep these as blank imports, even if they're imported above. - _ "crypto/sha1" - _ "crypto/sha256" - _ "crypto/sha512" -) - -type publicKeyInfo struct { - Raw asn1.RawContent - Algorithm pkix.AlgorithmIdentifier - PublicKey asn1.BitString -} - -type SignatureAlgorithm int - -const ( - UnknownSignatureAlgorithm SignatureAlgorithm = iota - - MD2WithRSA // Unsupported. - MD5WithRSA // Only supported for signing, not verification. - SHA1WithRSA // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. - SHA256WithRSA - SHA384WithRSA - SHA512WithRSA - DSAWithSHA1 // Unsupported. - DSAWithSHA256 // Unsupported. - ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. - ECDSAWithSHA256 - ECDSAWithSHA384 - ECDSAWithSHA512 - SHA256WithRSAPSS - SHA384WithRSAPSS - SHA512WithRSAPSS - PureEd25519 -) - -func (algo SignatureAlgorithm) String() string { - for _, details := range signatureAlgorithmDetails { - if details.algo == algo { - return details.name - } - } - return strconv.Itoa(int(algo)) -} - -type PublicKeyAlgorithm int - -const ( - UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota - RSA - DSA // Only supported for parsing. - ECDSA - Ed25519 -) - -var publicKeyAlgoName = [...]string{ - RSA: "RSA", - DSA: "DSA", - ECDSA: "ECDSA", - Ed25519: "Ed25519", -} - -func (algo PublicKeyAlgorithm) String() string { - if 0 < algo && int(algo) < len(publicKeyAlgoName) { - return publicKeyAlgoName[algo] - } - return strconv.Itoa(int(algo)) -} - -// OIDs for signature algorithms -// -// pkcs-1 OBJECT IDENTIFIER ::= { -// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } -// -// RFC 3279 2.2.1 RSA Signature Algorithms -// -// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } -// -// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } -// -// dsaWithSha1 OBJECT IDENTIFIER ::= { -// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } -// -// RFC 3279 2.2.3 ECDSA Signature Algorithm -// -// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { -// iso(1) member-body(2) us(840) ansi-x962(10045) -// signatures(4) ecdsa-with-SHA1(1)} -// -// RFC 4055 5 PKCS #1 Version 1.5 -// -// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } -// -// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } -// -// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } -// -// RFC 5758 3.1 DSA Signature Algorithms -// -// dsaWithSha256 OBJECT IDENTIFIER ::= { -// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) -// csor(3) algorithms(4) id-dsa-with-sha2(3) 2} -// -// RFC 5758 3.2 ECDSA Signature Algorithm -// -// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) -// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } -// -// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) -// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } -// -// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) -// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } -// -// RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers -// -// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } -var ( - oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} - oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} - oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} - oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} - oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} - oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} - oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} - oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} - oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} - oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} - oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} - oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} - oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} - - oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} - oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} - oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} - - oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} - - // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA - // but it's specified by ISO. Microsoft's makecert.exe has been known - // to produce certificates with this OID. - oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} -) - -var signatureAlgorithmDetails = []struct { - algo SignatureAlgorithm - name string - oid asn1.ObjectIdentifier - params asn1.RawValue - pubKeyAlgo PublicKeyAlgorithm - hash crypto.Hash - isRSAPSS bool -}{ - {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false}, - {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, - {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, - {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false}, - {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false}, - {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false}, - {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true}, - {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true}, - {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true}, - {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false}, - {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false}, - {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false}, - {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false}, - {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false}, - {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false}, - {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false}, -} - -var emptyRawValue = asn1.RawValue{} - -// DER encoded RSA PSS parameters for the -// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3. -// The parameters contain the following values: -// - hashAlgorithm contains the associated hash identifier with NULL parameters -// - maskGenAlgorithm always contains the default mgf1SHA1 identifier -// - saltLength contains the length of the associated hash -// - trailerField always contains the default trailerFieldBC value -var ( - pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}} - pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}} - pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}} -) - -// pssParameters reflects the parameters in an AlgorithmIdentifier that -// specifies RSA PSS. See RFC 3447, Appendix A.2.3. -type pssParameters struct { - // The following three fields are not marked as - // optional because the default values specify SHA-1, - // which is no longer suitable for use in signatures. - Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` - MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` - SaltLength int `asn1:"explicit,tag:2"` - TrailerField int `asn1:"optional,explicit,tag:3,default:1"` -} - -func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) stdx509.SignatureAlgorithm { - if ai.Algorithm.Equal(oidSignatureEd25519) { - // RFC 8410, Section 3 - // > For all of the OIDs, the parameters MUST be absent. - if len(ai.Parameters.FullBytes) != 0 { - return stdx509.UnknownSignatureAlgorithm - } - } - - if !ai.Algorithm.Equal(oidSignatureRSAPSS) { - for _, details := range signatureAlgorithmDetails { - if ai.Algorithm.Equal(details.oid) { - return stdx509.SignatureAlgorithm(details.algo) - } - } - return stdx509.UnknownSignatureAlgorithm - } - - // RSA PSS is special because it encodes important parameters - // in the Parameters. - - var params pssParameters - if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { - return stdx509.UnknownSignatureAlgorithm - } - - var mgf1HashFunc pkix.AlgorithmIdentifier - if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { - return stdx509.UnknownSignatureAlgorithm - } - - // PSS is greatly overburdened with options. This code forces them into - // three buckets by requiring that the MGF1 hash function always match the - // message hash function (as recommended in RFC 3447, Section 8.1), that the - // salt length matches the hash length, and that the trailer field has the - // default value. - if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) || - !params.MGF.Algorithm.Equal(oidMGF1) || - !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || - (len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) || - params.TrailerField != 1 { - return stdx509.UnknownSignatureAlgorithm - } - - switch { - case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: - return stdx509.SHA256WithRSAPSS - case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: - return stdx509.SHA384WithRSAPSS - case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: - return stdx509.SHA512WithRSAPSS - } - - return stdx509.UnknownSignatureAlgorithm -} - -var ( - // RFC 3279, 2.3 Public Key Algorithms - // - // pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) - // rsadsi(113549) pkcs(1) 1 } - // - // rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 } - // - // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) - // x9-57(10040) x9cm(4) 1 } - oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} - oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} - // RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters - // - // id-ecPublicKey OBJECT IDENTIFIER ::= { - // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } - oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} - // RFC 8410, Section 3 - // - // id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 } - // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } - oidPublicKeyX25519 = asn1.ObjectIdentifier{1, 3, 101, 110} - oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} -) - -// getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm -// identifier for public key types supported in certificates and CSRs. Marshal -// and Parse functions may support a different set of public key types. -func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) stdx509.PublicKeyAlgorithm { - switch { - case oid.Equal(oidPublicKeyRSA): - return stdx509.RSA - case oid.Equal(oidPublicKeyDSA): - return stdx509.DSA - case oid.Equal(oidPublicKeyECDSA): - return stdx509.ECDSA - case oid.Equal(oidPublicKeyEd25519): - return stdx509.Ed25519 - } - return stdx509.UnknownPublicKeyAlgorithm -} - -// RFC 5480, 2.1.1.1. Named Curve -// -// secp224r1 OBJECT IDENTIFIER ::= { -// iso(1) identified-organization(3) certicom(132) curve(0) 33 } -// -// secp256r1 OBJECT IDENTIFIER ::= { -// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) -// prime(1) 7 } -// -// secp384r1 OBJECT IDENTIFIER ::= { -// iso(1) identified-organization(3) certicom(132) curve(0) 34 } -// -// secp521r1 OBJECT IDENTIFIER ::= { -// iso(1) identified-organization(3) certicom(132) curve(0) 35 } -// -// NB: secp256r1 is equivalent to prime256v1 -var ( - oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} - oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} - oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} - oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} -) - -func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { - switch { - case oid.Equal(oidNamedCurveP224): - return elliptic.P224() - case oid.Equal(oidNamedCurveP256): - return elliptic.P256() - case oid.Equal(oidNamedCurveP384): - return elliptic.P384() - case oid.Equal(oidNamedCurveP521): - return elliptic.P521() - } - return nil -} - -// KeyUsage represents the set of actions that are valid for a given key. It's -// a bitmap of the KeyUsage* constants. -type KeyUsage int - -const ( - KeyUsageDigitalSignature KeyUsage = 1 << iota - KeyUsageContentCommitment - KeyUsageKeyEncipherment - KeyUsageDataEncipherment - KeyUsageKeyAgreement - KeyUsageCertSign - KeyUsageCRLSign - KeyUsageEncipherOnly - KeyUsageDecipherOnly -) - -// RFC 5280, 4.2.1.12 Extended Key Usage -// -// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } -// -// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } -// -// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } -// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } -// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } -// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } -// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } -// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } -var ( - oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} - oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} - oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} - oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} - oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} - oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} - oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} - oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} - oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} - oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} - oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} - oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} - oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} - oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} -) - -// ExtKeyUsage represents an extended set of actions that are valid for a given key. -// Each of the ExtKeyUsage* constants define a unique action. -type ExtKeyUsage int - -const ( - ExtKeyUsageAny ExtKeyUsage = iota - ExtKeyUsageServerAuth - ExtKeyUsageClientAuth - ExtKeyUsageCodeSigning - ExtKeyUsageEmailProtection - ExtKeyUsageIPSECEndSystem - ExtKeyUsageIPSECTunnel - ExtKeyUsageIPSECUser - ExtKeyUsageTimeStamping - ExtKeyUsageOCSPSigning - ExtKeyUsageMicrosoftServerGatedCrypto - ExtKeyUsageNetscapeServerGatedCrypto - ExtKeyUsageMicrosoftCommercialCodeSigning - ExtKeyUsageMicrosoftKernelCodeSigning -) - -// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. -var extKeyUsageOIDs = []struct { - extKeyUsage ExtKeyUsage - oid asn1.ObjectIdentifier -}{ - {ExtKeyUsageAny, oidExtKeyUsageAny}, - {ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth}, - {ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth}, - {ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning}, - {ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection}, - {ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem}, - {ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel}, - {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, - {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, - {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, - {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, - {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, - {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning}, - {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning}, -} - -func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { - for _, pair := range extKeyUsageOIDs { - if oid.Equal(pair.oid) { - return pair.extKeyUsage, true - } - } - return -} - -const ( - nameTypeEmail = 1 - nameTypeDNS = 2 - nameTypeURI = 6 - nameTypeIP = 7 -) - -var ( - oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1} -) - -var ( - oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} - oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} -) - -func isIA5String(s string) error { - for _, r := range s { - // Per RFC5280 "IA5String is limited to the set of ASCII characters" - if r > unicode.MaxASCII { - return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s) - } - } - - return nil -} diff --git a/vendor/github.com/smallstep/pkcs7/pkcs7.go b/vendor/github.com/smallstep/pkcs7/pkcs7.go index f6c6dfb..7a7598d 100644 --- a/vendor/github.com/smallstep/pkcs7/pkcs7.go +++ b/vendor/github.com/smallstep/pkcs7/pkcs7.go @@ -13,11 +13,8 @@ import ( "errors" "fmt" "sort" - "sync" _ "crypto/sha1" // for crypto.SHA1 - - legacyx509 "github.com/smallstep/pkcs7/internal/legacy/x509" ) // PKCS7 Represents a PKCS7 structure @@ -216,40 +213,6 @@ func parseEncryptedData(data []byte) (*PKCS7, error) { }, nil } -// SetFallbackLegacyX509CertificateParserEnabled enables parsing certificates -// embedded in a PKCS7 message using the logic from crypto/x509 from before -// Go 1.23. Go 1.23 introduced a breaking change in case a certificate contains -// a critical authority key identifier, which is the correct thing to do based -// on RFC 5280, but it breaks Windows devices performing the Simple Certificate -// Enrolment Protocol (SCEP), as the certificates embedded in those requests -// apparently have authority key identifier extensions marked critical. -// -// See https://go-review.googlesource.com/c/go/+/562341 for the change in the -// Go source. -// -// When [SetFallbackLegacyX509CertificateParserEnabled] is called with true, it -// enables parsing using the legacy crypto/x509 certificate parser. It'll first -// try to parse the certificates using the regular Go crypto/x509 package, but -// if it fails on the above case, it'll retry parsing the certificates using a -// copy of the crypto/x509 package based on Go 1.23, but skips checking the -// authority key identifier extension being critical or not. -func SetFallbackLegacyX509CertificateParserEnabled(v bool) { - legacyX509CertificateParser.Lock() - legacyX509CertificateParser.enabled = v - legacyX509CertificateParser.Unlock() -} - -var legacyX509CertificateParser struct { - sync.RWMutex - enabled bool -} - -func isLegacyX509ParserEnabled() bool { - legacyX509CertificateParser.RLock() - defer legacyX509CertificateParser.RUnlock() - return legacyX509CertificateParser.enabled -} - func (raw rawCertificates) Parse() ([]*x509.Certificate, error) { if len(raw.Raw) == 0 { return nil, nil @@ -260,14 +223,7 @@ func (raw rawCertificates) Parse() ([]*x509.Certificate, error) { return nil, err } - certificates, err := x509.ParseCertificates(val.Bytes) - if err != nil && err.Error() == "x509: authority key identifier incorrectly marked critical" { - if isLegacyX509ParserEnabled() { - certificates, err = legacyx509.ParseCertificates(val.Bytes) - } - } - - return certificates, err + return x509.ParseCertificates(val.Bytes) } func isCertMatchForIssuerAndSerial(cert *x509.Certificate, ias issuerAndSerial) bool { diff --git a/vendor/github.com/smallstep/pkcs7/verify.go b/vendor/github.com/smallstep/pkcs7/verify.go index 7525f91..2c6f32c 100644 --- a/vendor/github.com/smallstep/pkcs7/verify.go +++ b/vendor/github.com/smallstep/pkcs7/verify.go @@ -54,21 +54,6 @@ func (p7 *PKCS7) VerifyWithChainAtTime(truststore *x509.CertPool, currentTime ti return nil } -// SigningTimeNotValidError is returned when the signing time attribute -// falls outside of the signer certificate validity. -type SigningTimeNotValidError struct { - SigningTime time.Time - NotBefore time.Time // NotBefore of signer - NotAfter time.Time // NotAfter of signer -} - -func (e *SigningTimeNotValidError) Error() string { - return fmt.Sprintf("pkcs7: signing time %q is outside of certificate validity %q to %q", - e.SigningTime.Format(time.RFC3339), - e.NotBefore.Format(time.RFC3339), - e.NotAfter.Format(time.RFC3339)) -} - func verifySignatureAtTime(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool, currentTime time.Time) (err error) { signedData := p7.Content ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) @@ -106,11 +91,10 @@ func verifySignatureAtTime(p7 *PKCS7, signer signerInfo, truststore *x509.CertPo if err == nil { // signing time found, performing validity check if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) { - return &SigningTimeNotValidError{ - SigningTime: signingTime, - NotBefore: ee.NotBefore, - NotAfter: ee.NotAfter, - } + return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q", + signingTime.Format(time.RFC3339), + ee.NotBefore.Format(time.RFC3339), + ee.NotAfter.Format(time.RFC3339)) } } } @@ -162,11 +146,10 @@ func verifySignature(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool) (e if err == nil { // signing time found, performing validity check if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) { - return &SigningTimeNotValidError{ - SigningTime: signingTime, - NotBefore: ee.NotBefore, - NotAfter: ee.NotAfter, - } + return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q", + signingTime.Format(time.RFC3339), + ee.NotBefore.Format(time.RFC3339), + ee.NotAfter.Format(time.RFC3339)) } } } diff --git a/vendor/github.com/smallstep/pkcs7/verify_test_dsa.go b/vendor/github.com/smallstep/pkcs7/verify_test_dsa.go new file mode 100644 index 0000000..1eb05bc --- /dev/null +++ b/vendor/github.com/smallstep/pkcs7/verify_test_dsa.go @@ -0,0 +1,182 @@ +// +build go1.11 go1.12 go1.13 go1.14 go1.15 + +package pkcs7 + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + "io/ioutil" + "os" + "os/exec" + "testing" +) + +func TestVerifyEC2(t *testing.T) { + fixture := UnmarshalDSATestFixture(EC2IdentityDocumentFixture) + p7, err := Parse(fixture.Input) + if err != nil { + t.Errorf("Parse encountered unexpected error: %v", err) + } + p7.Certificates = []*x509.Certificate{fixture.Certificate} + if err := p7.Verify(); err != nil { + t.Errorf("Verify failed with error: %v", err) + } +} + +var EC2IdentityDocumentFixture = ` +-----BEGIN PKCS7----- +MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCA +JIAEggGmewogICJwcml2YXRlSXAiIDogIjE3Mi4zMC4wLjI1MiIsCiAgImRldnBh +eVByb2R1Y3RDb2RlcyIgOiBudWxsLAogICJhdmFpbGFiaWxpdHlab25lIiA6ICJ1 +cy1lYXN0LTFhIiwKICAidmVyc2lvbiIgOiAiMjAxMC0wOC0zMSIsCiAgImluc3Rh +bmNlSWQiIDogImktZjc5ZmU1NmMiLAogICJiaWxsaW5nUHJvZHVjdHMiIDogbnVs +bCwKICAiaW5zdGFuY2VUeXBlIiA6ICJ0Mi5taWNybyIsCiAgImFjY291bnRJZCIg +OiAiMTIxNjU5MDE0MzM0IiwKICAiaW1hZ2VJZCIgOiAiYW1pLWZjZTNjNjk2IiwK +ICAicGVuZGluZ1RpbWUiIDogIjIwMTYtMDQtMDhUMDM6MDE6MzhaIiwKICAiYXJj +aGl0ZWN0dXJlIiA6ICJ4ODZfNjQiLAogICJrZXJuZWxJZCIgOiBudWxsLAogICJy +YW1kaXNrSWQiIDogbnVsbCwKICAicmVnaW9uIiA6ICJ1cy1lYXN0LTEiCn0AAAAA +AAAxggEYMIIBFAIBATBpMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5n +dG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2Vi +IFNlcnZpY2VzIExMQwIJAJa6SNnlXhpnMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0B +CQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNjA0MDgwMzAxNDRaMCMG +CSqGSIb3DQEJBDEWBBTuUc28eBXmImAautC+wOjqcFCBVjAJBgcqhkjOOAQDBC8w +LQIVAKA54NxGHWWCz5InboDmY/GHs33nAhQ6O/ZI86NwjA9Vz3RNMUJrUPU5tAAA +AAAAAA== +-----END PKCS7----- +-----BEGIN CERTIFICATE----- +MIIC7TCCAq0CCQCWukjZ5V4aZzAJBgcqhkjOOAQDMFwxCzAJBgNVBAYTAlVTMRkw +FwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYD +VQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0xMjAxMDUxMjU2MTJaFw0z +ODAxMDUxMjU2MTJaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9u +IFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNl +cnZpY2VzIExMQzCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCjkvcS2bb1VQ4yt/5e +ih5OO6kK/n1Lzllr7D8ZwtQP8fOEpp5E2ng+D6Ud1Z1gYipr58Kj3nssSNpI6bX3 +VyIQzK7wLclnd/YozqNNmgIyZecN7EglK9ITHJLP+x8FtUpt3QbyYXJdmVMegN6P +hviYt5JH/nYl4hh3Pa1HJdskgQIVALVJ3ER11+Ko4tP6nwvHwh6+ERYRAoGBAI1j +k+tkqMVHuAFcvAGKocTgsjJem6/5qomzJuKDmbJNu9Qxw3rAotXau8Qe+MBcJl/U +hhy1KHVpCGl9fueQ2s6IL0CaO/buycU1CiYQk40KNHCcHfNiZbdlx1E9rpUp7bnF +lRa2v1ntMX3caRVDdbtPEWmdxSCYsYFDk4mZrOLBA4GEAAKBgEbmeve5f8LIE/Gf +MNmP9CM5eovQOGx5ho8WqD+aTebs+k2tn92BBPqeZqpWRa5P/+jrdKml1qx4llHW +MXrs3IgIb6+hUIB+S8dz8/mmO0bpr76RoZVCXYab2CZedFut7qc3WUH9+EUAH5mw +vSeDCOUMYQR7R9LINYwouHIziqQYMAkGByqGSM44BAMDLwAwLAIUWXBlk40xTwSw +7HX32MxXYruse9ACFBNGmdX2ZBrVNGrN9N2f6ROk0k9K +-----END CERTIFICATE-----` + +func TestDSASignWithOpenSSLAndVerify(t *testing.T) { + content := []byte(` +A ship in port is safe, +but that's not what ships are built for. +-- Grace Hopper`) + // write the content to a temp file + tmpContentFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_content") + if err != nil { + t.Fatal(err) + } + ioutil.WriteFile(tmpContentFile.Name(), content, 0755) + + // write the signer cert to a temp file + tmpSignerCertFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_signer") + if err != nil { + t.Fatal(err) + } + ioutil.WriteFile(tmpSignerCertFile.Name(), dsaPublicCert, 0755) + + // write the signer key to a temp file + tmpSignerKeyFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_key") + if err != nil { + t.Fatal(err) + } + ioutil.WriteFile(tmpSignerKeyFile.Name(), dsaPrivateKey, 0755) + + tmpSignedFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_signature") + if err != nil { + t.Fatal(err) + } + // call openssl to sign the content + opensslCMD := exec.Command("openssl", "smime", "-sign", "-nodetach", "-md", "sha1", + "-in", tmpContentFile.Name(), "-out", tmpSignedFile.Name(), + "-signer", tmpSignerCertFile.Name(), "-inkey", tmpSignerKeyFile.Name(), + "-certfile", tmpSignerCertFile.Name(), "-outform", "PEM") + out, err := opensslCMD.CombinedOutput() + if err != nil { + t.Fatalf("openssl command failed with %s: %s", err, out) + } + + // verify the signed content + pemSignature, err := ioutil.ReadFile(tmpSignedFile.Name()) + if err != nil { + t.Fatal(err) + } + fmt.Printf("%s\n", pemSignature) + derBlock, _ := pem.Decode(pemSignature) + if derBlock == nil { + t.Fatalf("failed to read DER block from signature PEM %s", tmpSignedFile.Name()) + } + p7, err := Parse(derBlock.Bytes) + if err != nil { + t.Fatalf("Parse encountered unexpected error: %v", err) + } + if err := p7.Verify(); err != nil { + t.Fatalf("Verify failed with error: %v", err) + } + os.Remove(tmpSignerCertFile.Name()) // clean up + os.Remove(tmpSignerKeyFile.Name()) // clean up + os.Remove(tmpContentFile.Name()) // clean up +} + +var dsaPrivateKey = []byte(`-----BEGIN PRIVATE KEY----- +MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdS +PO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVCl +pJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith +1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7L +vKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3 +zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo +g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUfW4aPdQBn9gJZp2KuNpzgHzvfsE= +-----END PRIVATE KEY-----`) + +var dsaPublicCert = []byte(`-----BEGIN CERTIFICATE----- +MIIDOjCCAvWgAwIBAgIEPCY/UDANBglghkgBZQMEAwIFADBsMRAwDgYDVQQGEwdV +bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD +VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du +MB4XDTE4MTAyMjEzNDMwN1oXDTQ2MDMwOTEzNDMwN1owbDEQMA4GA1UEBhMHVW5r +bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE +ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC +AbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADD +Hj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gE +exAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/Ii +Axmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4 +V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozI +puE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4Vrl +nwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKBgQDCriMPbEVBoRK4SOUeFwg7+VRf4TTp +rcOQC9IVVoCjXzuWEGrp3ZI7YWJSpFnSch4lk29RH8O0HpI/NOzKnOBtnKr782pt +1k/bJVMH9EaLd6MKnAVjrCDMYBB0MhebZ8QHY2elZZCWoqDYAcIDOsEx+m4NLErT +ypPnjS5M0jm1PKMhMB8wHQYDVR0OBBYEFC0Yt5XdM0Kc95IX8NQ8XRssGPx7MA0G +CWCGSAFlAwQDAgUAAzAAMC0CFQCIgQtrZZ9hdZG1ROhR5hc8nYEmbgIUAIlgC688 +qzy/7yePTlhlpj+ahMM= +-----END CERTIFICATE-----`) + +type DSATestFixture struct { + Input []byte + Certificate *x509.Certificate +} + +func UnmarshalDSATestFixture(testPEMBlock string) DSATestFixture { + var result DSATestFixture + var derBlock *pem.Block + var pemBlock = []byte(testPEMBlock) + for { + derBlock, pemBlock = pem.Decode(pemBlock) + if derBlock == nil { + break + } + switch derBlock.Type { + case "PKCS7": + result.Input = derBlock.Bytes + case "CERTIFICATE": + result.Certificate, _ = x509.ParseCertificate(derBlock.Bytes) + } + } + + return result +} diff --git a/vendor/github.com/smallstep/scep/scep.go b/vendor/github.com/smallstep/scep/scep.go index 8004af2..d922866 100644 --- a/vendor/github.com/smallstep/scep/scep.go +++ b/vendor/github.com/smallstep/scep/scep.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" + "github.com/go-kit/kit/log/level" "github.com/smallstep/pkcs7" "github.com/smallstep/scep/cryptoutil" @@ -26,6 +27,12 @@ var ( errUnknownMessageType = errors.New("scep: unknown messageType") ) +// prepare the go-kit leveled logging configuration +var ( + levelKey = level.Key() + levelDebug = level.DebugValue() +) + // The MessageType attribute specifies the type of operation performed // by the transaction. This attribute MUST be included in all PKI // messages. @@ -142,7 +149,7 @@ func WithLogger(logger Logger) Option { } // WithCACerts adds option CA certificates to the SCEP operations. -// Note: This changes the verification behavior of PKCS#7 messages. If this +// Note: This changes the verification behavior of PKCS #7 messages. If this // option is specified, only caCerts will be used as expected signers. func WithCACerts(caCerts []*x509.Certificate) Option { return func(c *config) { @@ -154,7 +161,7 @@ func WithCACerts(caCerts []*x509.Certificate) Option { // operations. // This option is effective when used with NewCSRRequest function. In // this case, only certificates selected with the certsSelector will be used -// as the PKCS#7 message recipients. +// as the PKCS #7 message recipients. func WithCertsSelector(selector CertsSelector) Option { return func(c *config) { c.certsSelector = selector @@ -191,7 +198,7 @@ type PKIMessage struct { Recipients []*x509.Certificate // Signer info - SignerKey crypto.PrivateKey + SignerKey *rsa.PrivateKey SignerCert *x509.Certificate logger Logger @@ -240,7 +247,7 @@ func ParsePKIMessage(data []byte, opts ...Option) (*PKIMessage, error) { // signatures have an alternate means of obtaining necessary certificates. // In SCEP case, an alternate means is to use GetCaCert request. // Note: The https://github.com/jscep/jscep implementation logs a warning if - // no certificates were found for signers in the PKCS#7 received from the + // no certificates were found for signers in the PKCS #7 received from the // server, but the certificates obtained from GetCaCert request are still // used for decoding the message. p7.Certificates = conf.caCerts @@ -269,6 +276,7 @@ func ParsePKIMessage(data []byte, opts ...Option) (*PKIMessage, error) { } msg.logger.Log( + levelKey, levelDebug, "msg", "parsed scep pkiMessage", "scep_message_type", msgType, "transaction_id", tID, @@ -335,22 +343,8 @@ func (msg *PKIMessage) parseMessageType() error { } } -// DecryptPKIEnvelope decrypts the PKCS#7 envelopedData inside the SCEP PKIMessage -func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key crypto.PrivateKey) error { - if cert == nil { - return errors.New("scep: cert must not be nil") - } - if key == nil { - return errors.New("scep: key must not be nil") - } - decrypter, ok := key.(crypto.Decrypter) - if !ok { - return errors.New("scep: private key does not implement crypto.Decrypter") - } - if _, ok := decrypter.Public().(*rsa.PublicKey); !ok { - return fmt.Errorf("scep: key.Public() returned type %T; expected *rsa.PublicKey", decrypter.Public()) - } - +// DecryptPKIEnvelope decrypts the pkcs envelopedData inside the SCEP PKIMessage +func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key *rsa.PrivateKey) error { p7, err := pkcs7.Parse(msg.p7.Content) if err != nil { return err @@ -361,6 +355,7 @@ func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key crypto.Pri } logKeyVals := []interface{}{ + levelKey, levelDebug, "msg", "decrypt pkiEnvelope", } defer func() { msg.logger.Log(logKeyVals...) }() @@ -398,8 +393,7 @@ func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key crypto.Pri } } -// Fail returns a new PKIMessage with CertRep data indicating a failure -func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth crypto.PrivateKey, info FailInfo) (*PKIMessage, error) { +func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, info FailInfo) (*PKIMessage, error) { config := pkcs7.SignerInfoConfig{ ExtraSignedAttributes: []pkcs7.Attribute{ { @@ -462,9 +456,9 @@ func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth crypto.PrivateKey } // Success returns a new PKIMessage with CertRep data using an already-issued certificate -func (msg *PKIMessage) Success(crtAuth *x509.Certificate, keyAuth crypto.PrivateKey, crt *x509.Certificate) (*PKIMessage, error) { +func (msg *PKIMessage) Success(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, crt *x509.Certificate) (*PKIMessage, error) { // check if CSRReqMessage has already been decrypted - if msg.CSRReqMessage.CSR == nil { // TODO(hslatman): remove this; just require decryption before, so that we can make keyAuth a crypto.Signer + if msg.CSRReqMessage.CSR == nil { if err := msg.DecryptPKIEnvelope(crtAuth, keyAuth); err != nil { return nil, err } @@ -544,7 +538,7 @@ func (msg *PKIMessage) Success(crtAuth *x509.Certificate, keyAuth crypto.Private return crepMsg, nil } -// DegenerateCertificates creates degenerate certificates PKCS#7 type +// DegenerateCertificates creates degenerate certificates pkcs#7 type func DegenerateCertificates(certs []*x509.Certificate) ([]byte, error) { var buf bytes.Buffer for _, cert := range certs { @@ -557,7 +551,7 @@ func DegenerateCertificates(certs []*x509.Certificate) ([]byte, error) { return degenerate, nil } -// CACerts extract CA Certificate or chain from PKCS#7 degenerate signed data +// CACerts extract CA Certificate or chain from pkcs7 degenerate signed data func CACerts(data []byte) ([]*x509.Certificate, error) { p7, err := pkcs7.Parse(data) if err != nil { @@ -604,6 +598,7 @@ func NewCSRRequest(csr *x509.CertificateRequest, tmpl *PKIMessage, opts ...Optio } conf.logger.Log( + levelKey, levelDebug, "msg", "creating SCEP CSR request", "transaction_id", tID, "signer_cn", tmpl.SignerCert.Subject.CommonName, diff --git a/vendor/github.com/smallstep/scep/x509util/x509util.go b/vendor/github.com/smallstep/scep/x509util/x509util.go index 53f9517..0e65409 100644 --- a/vendor/github.com/smallstep/scep/x509util/x509util.go +++ b/vendor/github.com/smallstep/scep/x509util/x509util.go @@ -55,7 +55,7 @@ type CertificateRequest struct { // challengePassword attribute. // // See https://github.com/golang/go/issues/15995 -func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv crypto.PrivateKey) (csr []byte, err error) { +func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) { if template.ChallengePassword == "" { // if no challenge password, return a stdlib CSR. return x509.CreateCertificateRequest(rand, &template.CertificateRequest, priv) |
