pull/1525/merge
Venky 4 months ago committed by GitHub
commit b4d3920b3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -18,6 +18,7 @@ type Authorization struct {
Wildcard bool `json:"wildcard"`
ExpiresAt time.Time `json:"expires"`
Error *Error `json:"error,omitempty"`
ExtraIdentifiers []string `json:"extraIdentifiers,omitempty"`
}
// ToLog enables response logging.

@ -417,7 +417,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
// identifiers.
//
// Note: We might want to use an external service for this.
if data.UDID != ch.Value && data.SerialNumber != ch.Value {
if !SkipPermanentIdentiferValidation && (data.UDID != ch.Value) && (data.SerialNumber != ch.Value) {
subproblem := NewSubproblemWithIdentifier(
ErrorRejectedIdentifierType,
Identifier{Type: "permanent-identifier", Value: ch.Value},
@ -445,7 +445,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
// certificate with the challenged Order value.
//
// Note: We might want to use an external service for this.
if data.SerialNumber != ch.Value {
if !SkipPermanentIdentiferValidation && (data.SerialNumber != ch.Value) {
subproblem := NewSubproblemWithIdentifier(
ErrorRejectedIdentifierType,
Identifier{Type: "permanent-identifier", Value: ch.Value},
@ -456,6 +456,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
// Update attestation key fingerprint to compare against the CSR
az.Fingerprint = data.Fingerprint
az.ExtraIdentifiers = []string{data.SerialNumber, p.AttObj}
case "tpm":
data, err := doTPMAttestationFormat(ctx, prov, ch, jwk, &att)
@ -475,7 +476,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
// haven't implemented a way for AK certs requested by the CLI to always contain the requested
// PermanentIdentifier. Omitting the check below doesn't allow just any request, as the Order can
// still fail if the challenge value isn't equal to the CSR subject.
if len(data.PermanentIdentifiers) > 0 && !slices.Contains(data.PermanentIdentifiers, ch.Value) { // TODO(hs): add support for HardwareModuleName
if (!SkipPermanentIdentiferValidation) && (len(data.PermanentIdentifiers) > 0) && (!slices.Contains(data.PermanentIdentifiers, ch.Value)) { // TODO(hs): add support for HardwareModuleName
subproblem := NewSubproblemWithIdentifier(
ErrorRejectedIdentifierType,
Identifier{Type: "permanent-identifier", Value: ch.Value},
@ -486,6 +487,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
// Update attestation key fingerprint to compare against the CSR
az.Fingerprint = data.Fingerprint
default:
return storeError(ctx, db, ch, true, NewDetailedError(ErrorBadAttestationStatementType, "unsupported attestation object format %q", format))
}
@ -498,7 +500,7 @@ func deviceAttest01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose
// Store the fingerprint in the authorization.
//
// TODO: add method to update authorization and challenge atomically.
if az.Fingerprint != "" {
if az.Fingerprint != "" || az.ExtraIdentifiers != nil {
if err := db.UpdateAuthorization(ctx, az); err != nil {
return WrapErrorISE(err, "error updating authorization")
}

@ -40,6 +40,13 @@ func NewContext(ctx context.Context, db DB, client Client, linker Linker, fn Pre
return ctx
}
// SkipPermanentIdentiferValidation allows one to bypass the code which validates
// that a) that the attested UUID or serial for "device-attest-01" request match
// the permanent identifier and b) that the CN presented in the final CSRs match the permanent
// identifier. The logic to bypass this is to allow external CAs to control the validation temporarily
// Setting this at true at this global level is extremely discouraged (unless you know what you are doing)
var SkipPermanentIdentiferValidation bool
// PrerequisitesChecker is a function that checks if all prerequisites for
// serving ACME are met by the CA configuration.
type PrerequisitesChecker func(ctx context.Context) (bool, error)

@ -23,6 +23,7 @@ type dbAuthz struct {
CreatedAt time.Time `json:"createdAt"`
ExpiresAt time.Time `json:"expiresAt"`
Error *acme.Error `json:"error"`
ExtraIdentifiers []string `json:"extraIdentifiers,omitempty"`
}
func (ba *dbAuthz) clone() *dbAuthz {
@ -71,6 +72,7 @@ func (db *DB) GetAuthorization(ctx context.Context, id string) (*acme.Authorizat
ExpiresAt: dbaz.ExpiresAt,
Token: dbaz.Token,
Fingerprint: dbaz.Fingerprint,
ExtraIdentifiers: dbaz.ExtraIdentifiers,
Error: dbaz.Error,
}, nil
}
@ -101,6 +103,7 @@ func (db *DB) CreateAuthorization(ctx context.Context, az *acme.Authorization) e
Token: az.Token,
Fingerprint: az.Fingerprint,
Wildcard: az.Wildcard,
ExtraIdentifiers: nil,
}
return db.save(ctx, az.ID, dbaz, nil, "authz", authzTable)
@ -116,6 +119,7 @@ func (db *DB) UpdateAuthorization(ctx context.Context, az *acme.Authorization) e
nu := old.clone()
nu.Status = az.Status
nu.Fingerprint = az.Fingerprint
nu.ExtraIdentifiers = az.ExtraIdentifiers
nu.Error = az.Error
return db.save(ctx, old.ID, nu, old, "authz", authzTable)
}
@ -149,6 +153,7 @@ func (db *DB) GetAuthorizationsByAccountID(_ context.Context, accountID string)
Token: dbaz.Token,
Fingerprint: dbaz.Fingerprint,
Error: dbaz.Error,
ExtraIdentifiers: dbaz.ExtraIdentifiers,
})
}

@ -148,6 +148,21 @@ func (o *Order) getAuthorizationFingerprint(ctx context.Context, db DB) (string,
return "", nil
}
func (o *Order) getAuthorizationExtraIdentifiers(ctx context.Context, db DB) ([]string, error) {
for _, azID := range o.AuthorizationIDs {
az, err := db.GetAuthorization(ctx, azID)
if err != nil {
return nil, WrapErrorISE(err, "error getting authorization %q", azID)
}
// There's no point on reading all the authorizations as there will
// be only one for a permanent identifier.
if az.ExtraIdentifiers != nil {
return az.ExtraIdentifiers, nil
}
}
return nil, nil
}
// Finalize signs a certificate if the necessary conditions for Order completion
// have been met.
//
@ -191,6 +206,11 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques
}
}
extraIdentifiers, err := o.getAuthorizationExtraIdentifiers(ctx, db)
if err != nil {
return err
}
// canonicalize the CSR to allow for comparison
csr = canonicalize(csr)
@ -211,7 +231,7 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques
// is rejected, because the Common Name hasn't been challenged in that case. This
// could result in unauthorized access if a relying system relies on the Common
// Name in its authorization logic.
if csr.Subject.CommonName != "" && csr.Subject.CommonName != permanentIdentifier {
if !SkipPermanentIdentiferValidation && (csr.Subject.CommonName != "") && (csr.Subject.CommonName != permanentIdentifier) {
return NewError(ErrorBadCSRType, "CSR Subject Common Name does not match identifiers exactly: "+
"CSR Subject Common Name = %s, Order Permanent Identifier = %s", csr.Subject.CommonName, permanentIdentifier)
}
@ -228,6 +248,7 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques
})
extraOptions = append(extraOptions, provisioner.AttestationData{
PermanentIdentifier: permanentIdentifier,
ExtraIdentifiers: extraIdentifiers,
})
} else {
defaultTemplate = x509util.DefaultLeafTemplate

@ -81,7 +81,8 @@ func (fn CertificateEnforcerFunc) Enforce(cert *x509.Certificate) error {
// AttestationData is a SignOption used to pass attestation information to the
// sign methods.
type AttestationData struct {
PermanentIdentifier string
PermanentIdentifier string //
ExtraIdentifiers []string
}
// defaultPublicKeyValidator validates the public key of a certificate request.

@ -272,6 +272,17 @@ func (a *Authority) signX509(csr *x509.CertificateRequest, signOpts provisioner.
)
}
var clientIdentifier string
var extraIdentifiers []string
if attData != nil {
if attData.PermanentIdentifier != "" {
clientIdentifier = attData.PermanentIdentifier
}
if attData.ExtraIdentifiers != nil {
extraIdentifiers = attData.ExtraIdentifiers
}
}
// Sign certificate
lifetime := leaf.NotAfter.Sub(leaf.NotBefore.Add(signOpts.Backdate))
@ -281,6 +292,8 @@ func (a *Authority) signX509(csr *x509.CertificateRequest, signOpts provisioner.
Lifetime: lifetime,
Backdate: signOpts.Backdate,
Provisioner: pInfo,
ClientIdentifier: clientIdentifier,
ExtraIdentifiers: extraIdentifiers,
})
if err != nil {
return nil, prov, errs.Wrap(http.StatusInternalServerError, err, "authority.Sign; error creating certificate", opts...)

@ -59,6 +59,8 @@ type CreateCertificateRequest struct {
RequestID string
Provisioner *ProvisionerInfo
IsCAServerCert bool
ClientIdentifier string // any identifier token (can be any arbitrary token/blob interpretable by the CA)
ExtraIdentifiers []string // any additional identifier ( interpretable by the CA such as serial, UDID of device)
}
// ProvisionerInfo contains information of the provisioner used to authorize a

@ -165,4 +165,5 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/gotestsum v1.10.1 // indirect
)

@ -351,6 +351,7 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
@ -471,6 +472,7 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
@ -555,6 +557,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
@ -580,6 +583,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -623,6 +627,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

Loading…
Cancel
Save