fleet/server/datastore/mysql/wstep.go
gillespi314 410cbc3972
Add certificate management for Microsoft MDM (WSTEP) (#12543)
Issue #12261

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [ ] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)
- [ ] Documented any permissions changes
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.
- [ ] Added/updated tests
- [ ] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [ ] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2023-06-29 19:31:53 -03:00

70 lines
2.0 KiB
Go

package mysql
import (
"context"
"crypto/sha256"
"crypto/x509"
"errors"
"fmt"
"math/big"
"strings"
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
microsoft_mdm "github.com/fleetdm/fleet/v4/server/mdm/microsoft"
)
// CertStore implements storage tasks associated with MS-WSTEP messages in the MS-MDE2
// protocol. It is implemented by fleet.Datastore.
var _ microsoft_mdm.CertStore = (*Datastore)(nil)
// WSTEPStoreCertificate stores a certificate under the given name.
//
// If the provided certificate has empty crt.Subject.CommonName,
// then the hex sha256 of the crt.Raw is used as name.
func (ds *Datastore) WSTEPStoreCertificate(ctx context.Context, name string, crt *x509.Certificate) error {
if crt.Subject.CommonName == "" {
name = fmt.Sprintf("%x", sha256.Sum256(crt.Raw))
}
if !crt.SerialNumber.IsInt64() {
return errors.New("cannot represent serial number as int64")
}
certPEM := apple_mdm.EncodeCertPEM(crt)
_, err := ds.writer(ctx).ExecContext(ctx, `
INSERT INTO wstep_certificates
(serial, name, not_valid_before, not_valid_after, certificate_pem)
VALUES
(?, ?, ?, ?, ?)`,
crt.SerialNumber.Int64(),
name,
crt.NotBefore,
crt.NotAfter,
certPEM,
)
return err
}
// WSTEPNewSerial allocates and returns a new (increasing) serial number.
func (ds *Datastore) WSTEPNewSerial(ctx context.Context) (*big.Int, error) {
result, err := ds.writer(ctx).ExecContext(ctx, `INSERT INTO wstep_serials () VALUES ();`)
if err != nil {
return nil, err
}
lid, err := result.LastInsertId() // TODO: ok if sequential and not random?
if err != nil {
return nil, err
}
// TODO: check maxSerialNumber?
return big.NewInt(lid), nil
}
func (ds *Datastore) WSTEPAssociateCertHash(ctx context.Context, deviceUUID string, hash string) error {
_, err := ds.writer(ctx).ExecContext(ctx, `
INSERT INTO wstep_cert_auth_associations (id, sha256) VALUES (?, ?) AS new
ON DUPLICATE KEY
UPDATE sha256 = new.sha256;`,
deviceUUID,
strings.ToUpper(hash), // TODO: confirm if this is necessary
)
return err
}