Skip to content

Add SCEP endpoint for host identity. - #30589

Merged
lucasmrod merged 11 commits into
mainfrom
victor/30458-tpm-scep-endpoint
Jul 11, 2025
Merged

Add SCEP endpoint for host identity.#30589
lucasmrod merged 11 commits into
mainfrom
victor/30458-tpm-scep-endpoint

Conversation

@getvictor

@getvictor getvictor commented Jul 7, 2025

Copy link
Copy Markdown
Member

Fixes #30458

Contributor docs PR: #30651

Checklist for submitter

  • We will add changes file later.
  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements)
  • If database migrations are included, checked table schema to confirm autoupdate
  • For database migrations:
    • Checked schema for all modified table for columns that will auto-update timestamps during migration.
    • Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects.
    • Ensured the correct collation is explicitly set for character columns (COLLATE utf8mb4_unicode_ci).
  • Added/updated automated tests
  • Did not do manual QA since the SCEP client I have doesn't support ECC. Will rely on next subtasks for manual QA.

Summary by CodeRabbit

  • New Features

    • Introduced Host Identity SCEP (Simple Certificate Enrollment Protocol) support, enabling secure host identity certificate enrollment and management.
    • Added new API endpoints for Host Identity SCEP, including certificate issuance and retrieval.
    • Implemented MySQL-backed storage and management for host identity SCEP certificates and serials.
    • Added new database tables for storing host identity SCEP certificates and serial numbers.
    • Provided utilities for encoding certificates and keys, and handling ECDSA public keys.
  • Bug Fixes

    • None.
  • Tests

    • Added comprehensive integration and unit tests for Host Identity SCEP functionality, including certificate issuance, validation, and error scenarios.
  • Chores

    • Updated test utilities to support unique test names and new SCEP storage options.
    • Extended mock datastore and interfaces for new host identity certificate methods.
  • Documentation

    • Added comments and documentation for new SCEP-related interfaces, methods, and database schema changes.

@coderabbitai

coderabbitai Bot commented Jul 7, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This change introduces a new SCEP (Simple Certificate Enrollment Protocol) endpoint for issuing host identity certificates at /api/fleet/orbit/host_identity/scep. It adds new database tables, service logic, certificate handling, and comprehensive integration and unit tests. The implementation supports ECC P-256 and P-384, manages unique CNs, stores raw public keys, and enforces enrollment secrets.

Changes

Files/Paths Change Summary
ee/server/service/hostidentity/scep.go, config.go, depot/depot.go, types/host_identity_certificates.go Implements SCEP service, asset initialization, MySQL-backed SCEP depot, and host identity certificate types
ee/server/service/hostidentity/types/host_identity_certificates_test.go Adds unit tests for ECDSA public key marshaling/unmarshaling
ee/server/integrationtest/hostidentity/hostidscep_test.go, suite.go Adds integration test suite for SCEP endpoint, including success and failure scenarios
server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go, schema.sql Adds migrations and schema for host_identity_scep_certificates and host_identity_scep_serials tables
server/datastore/mysql/host_identity_scep.go, server/fleet/datastore.go, server/mock/datastore_mock.go Adds datastore methods and mocks for host identity certificate retrieval
server/datastore/mysql/mysql.go Adds methods to create Host Identity SCEP depot and renames Apple SCEP depot method
cmd/fleet/serve.go, server/service/testing_utils.go, server/service/integrationtest/suite.go Registers Host Identity SCEP service in server and test setup
server/fleet/mdm.go Adds asset name constants for host identity CA cert and key
server/mdm/apple/cert.go, server/mdm/apple/util.go, server/mdm/scep/depot/fleet.go Moves certificate/key generation and encoding utilities to new locations
pkg/certificate/certificate.go, server/service/mdm.go, server/datastore/mysql/scep.go, server/datastore/mysql/wstep.go Refactors certificate PEM encoding to a shared package
server/datastore/mysql/common_mysql/testing_utils/testing_utils.go Adds support for unique test names in datastore test options
Makefile Adds host identity types package to fast test list
server/cron/calendar_cron_test.go Removes t.Parallel() from a test (minor, unrelated to main feature)

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SCEP Endpoint (/api/fleet/orbit/host_identity/scep)
    participant SCEP Service
    participant Datastore
    participant SCEP Depot

    Client->>SCEP Endpoint: PKIOperation (CSR w/ ECC key, challenge password)
    SCEP Endpoint->>SCEP Service: PKIOperation(data)
    SCEP Service->>Datastore: Verify enrollment secret
    Datastore-->>SCEP Service: Secret valid/invalid
    alt Secret valid
        SCEP Service->>SCEP Depot: Sign CSR, store cert (unique CN, ECC only)
        SCEP Depot->>Datastore: Store cert, raw public key, manage revocation
        SCEP Depot-->>SCEP Service: Signed certificate
        SCEP Service-->>SCEP Endpoint: SCEP success response (certificate)
        SCEP Endpoint-->>Client: Success (certificate)
    else Secret invalid or error
        SCEP Service-->>SCEP Endpoint: SCEP failure response
        SCEP Endpoint-->>Client: Failure
    end
Loading

Assessment against linked issues

Objective Addressed Explanation
New SCEP endpoint at /api/fleet/orbit/host_identity/scep for host_identity certs (#30458)
Challenge: enrollment secret is required for SCEP requests (#30458)
Supported certs: ECC NIST P-256, P-384 only; reject others (#30458)
Expiration: issued certs valid for 1 year (#30458)
CA keypair is independent, stored in mdm_config_assets, not coupled to Apple MDM (#30458)
Certs stored in host_identity_scep_certificates table, with raw public key (04 X
Cert CN is unique, new cert overwrites old for same CN, old certs are revoked not deleted (#30458)
Store raw public key as uncompressed EC point, support for P-256/P-384, with curve inference (#30458)

Poem

A SCEP endpoint hops into view,
For host identities—fresh and new!
ECC keys, both big and small,
P-256, P-384—Fleet now serves them all.
With secrets checked and certs in store,
🐇 The warren’s secure, and hosts can roar!
Hooray for certs—let’s issue more!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@getvictor getvictor added the :ai Request AI PR review label Jul 7, 2025
@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
ee/server/service/hostidscep/scep.go (2)

91-97: Improve error message accuracy

The error message says "parsing SCEP certificate" but the operation is retrieving the certificate from storage, not parsing it.

-		return nil, 0, ctxerr.Wrap(ctx, err, "parsing SCEP certificate")
+		return nil, 0, ctxerr.Wrap(ctx, err, "retrieving SCEP CA certificate")

108-111: Maintain error message consistency

Same issue as in GetCACert - the error message should indicate retrieval, not parsing.

-		return nil, ctxerr.Wrap(ctx, err, "parsing SCEP certificate")
+		return nil, ctxerr.Wrap(ctx, err, "retrieving SCEP CA certificate")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0609b9b and 8978165.

📒 Files selected for processing (10)
  • ee/server/service/hostidscep/config.go (1 hunks)
  • ee/server/service/hostidscep/scep.go (1 hunks)
  • pkg/certificate/certificate.go (2 hunks)
  • server/datastore/mysql/scep.go (2 hunks)
  • server/datastore/mysql/wstep.go (2 hunks)
  • server/fleet/mdm.go (1 hunks)
  • server/mdm/apple/cert.go (1 hunks)
  • server/mdm/apple/util.go (0 hunks)
  • server/mdm/scep/depot/fleet.go (1 hunks)
  • server/service/mdm.go (3 hunks)
💤 Files with no reviewable changes (1)
  • server/mdm/apple/util.go
🧰 Additional context used
🧬 Code Graph Analysis (7)
server/datastore/mysql/wstep.go (1)
pkg/certificate/certificate.go (1)
  • EncodeCertPEM (244-250)
server/datastore/mysql/scep.go (1)
pkg/certificate/certificate.go (1)
  • EncodeCertPEM (244-250)
ee/server/service/hostidscep/config.go (5)
server/contexts/license/license.go (1)
  • IsPremium (30-35)
server/fleet/mdm.go (4)
  • MDMAssetName (729-729)
  • MDMAssetHostIdentityCACert (771-771)
  • MDMAssetHostIdentityCAKey (773-773)
  • MDMConfigAsset (776-780)
server/mdm/apple/cert.go (1)
  • NewSCEPCACertKey (204-206)
server/mdm/scep/depot/fleet.go (1)
  • NewSCEPCACertKey (11-33)
pkg/certificate/certificate.go (2)
  • EncodeCertPEM (244-250)
  • EncodePrivateKeyPEM (253-259)
server/mdm/scep/depot/fleet.go (2)
server/mdm/apple/cert.go (1)
  • NewSCEPCACertKey (204-206)
pkg/certificate/certificate.go (1)
  • Certificate (132-136)
ee/server/service/hostidscep/scep.go (3)
server/fleet/datastore.go (2)
  • MDMAppleStore (2226-2231)
  • MDMAssetRetriever (2233-2237)
server/mdm/scep/server/endpoint.go (2)
  • MakeServerEndpoints (98-104)
  • EndpointLoggingMiddleware (215-231)
server/mdm/scep/server/transport.go (1)
  • MakeHTTPHandler (20-41)
server/service/mdm.go (2)
pkg/certificate/certificate.go (2)
  • EncodeCertPEM (244-250)
  • EncodePrivateKeyPEM (253-259)
server/fleet/mdm.go (3)
  • MDMAssetCACert (734-734)
  • MDMAssetCAKey (737-737)
  • MDMAssetAPNSKey (740-740)
server/mdm/apple/cert.go (1)
server/mdm/scep/depot/fleet.go (1)
  • NewSCEPCACertKey (11-33)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (31)
  • GitHub Check: test-go (mysql, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (main, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (service, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (mysql, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (service, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (vuln, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (vuln, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: build-binaries
  • GitHub Check: test-packaging (ubuntu-latest)
  • GitHub Check: test-go (fast, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (integration-mdm, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-enterprise, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-packaging (macos-15)
  • GitHub Check: test-go (fleetctl, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (main, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: Analyze (go)
  • GitHub Check: test-go (integration-core, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-core, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (integration-mdm, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: test-go (fleetctl, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (integration-enterprise, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: publish
  • GitHub Check: test-packaging (ubuntu-latest, local)
  • GitHub Check: test-packaging (ubuntu-latest, remote)
  • GitHub Check: test-preview (ubuntu-latest)
  • GitHub Check: check-doc-gen
  • GitHub Check: lint (windows-latest)
  • GitHub Check: lint (macos-latest)
  • GitHub Check: lint (ubuntu-latest)
  • GitHub Check: test-db-changes
🔇 Additional comments (13)
server/datastore/mysql/wstep.go (1)

12-12: LGTM: Clean refactoring to centralized certificate package

The import change and function call update correctly use the new centralized certificate.EncodeCertPEM function, which provides identical functionality to the previous Apple MDM-specific implementation.

Also applies to: 31-31

server/datastore/mysql/scep.go (1)

14-14: LGTM: Consistent refactoring pattern

The changes correctly update the import and function call to use the centralized certificate.EncodeCertPEM function, maintaining the same functionality while following the consistent refactoring pattern across the codebase.

Also applies to: 93-93

server/fleet/mdm.go (1)

770-773: LGTM: Well-named constants for host identity SCEP

The new constants follow the established naming pattern and provide clear, descriptive names for the host identity CA certificate and key assets. This supports the new host identity SCEP functionality mentioned in the PR objectives.

server/mdm/apple/cert.go (1)

205-205: LGTM: Proper delegation to centralized implementation

The refactoring correctly delegates to depot.NewSCEPCACertKey(), which centralizes the SCEP CA certificate/key generation logic while maintaining the same function signature and behavior.

pkg/certificate/certificate.go (2)

6-6: LGTM: Required imports for PEM encoding functions

The new imports for crypto/rsa and encoding/pem are correctly added to support the new PEM encoding functions.

Also applies to: 9-9


243-259: LGTM: Well-implemented centralized PEM encoding functions

The new EncodeCertPEM and EncodePrivateKeyPEM functions correctly implement PEM encoding:

  • Uses standard PEM block types ("CERTIFICATE" and "RSA PRIVATE KEY")
  • Proper use of x509.MarshalPKCS1PrivateKey for RSA keys
  • Consistent with the previous Apple MDM-specific implementations
  • Centralizes this functionality for reuse across the codebase

This successfully consolidates PEM encoding logic that was previously scattered across different packages.

server/service/mdm.go (3)

24-24: LGTM: Import addition supports refactoring

The new certificate package import is appropriately added to support the refactored PEM encoding functions.


213-215: LGTM: Clean refactoring to generic encoding functions

The replacement of Apple MDM-specific PEM encoding functions with generic certificate package functions improves code modularity while maintaining identical functionality.


2529-2531: LGTM: Consistent refactoring of encoding functions

The PEM encoding function calls are consistently updated to use the generic certificate package, completing the refactoring started in the RequestMDMAppleCSR method.

server/mdm/scep/depot/fleet.go (2)

35-41: LGTM: Secure key generation with appropriate key size

The RSA key size of 2048 bits correctly addresses Apple's CSR requirements. The use of crypto/rand ensures cryptographically secure random number generation for the private key.


11-33: Certificate creation helper functions verified and approved

The NewCACert, WithYears, and WithCommonName functions are properly implemented in server/mdm/scep/depot/cacert.go, so the CA certificate generation logic in NewSCEPCACertKey is sound. No further changes required.

ee/server/service/hostidscep/config.go (1)

30-52: No additional uniqueness safeguards needed—DB constraint already prevents duplicates

The mdm_config_assets table defines a unique index on (name, deletion_uuid), and InsertMDMConfigAssets will error if you try to insert the same asset name twice. Because deletion_uuid defaults to the empty string, any second insert of the same name will hit that unique‐key violation.

Rather than adding a database constraint, you should catch and ignore “duplicate key” errors around the insert to make the init routine safe for concurrent startup. For example:

if err := ds.InsertMDMConfigAssets(ctx, assets, nil); err != nil {
    // If the error is a MySQL/SQLite duplicate‐key violation, ignore it
    if !isDuplicateKeyErr(err) {
        return fmt.Errorf("inserting host identity SCEP assets: %w", err)
    }
}

• Add an isDuplicateKeyErr(error) bool helper that inspects the SQL error code for a unique‐constraint violation.
• Leave the existing UNIQUE INDEX (idx_mdm_config_assets_name_deletion_uuid) in place.

This change ensures only one instance creates the assets while others simply proceed when they observe “already exists.”

ee/server/service/hostidscep/scep.go (1)

66-89: Well-designed capability declaration

The detailed documentation of supported and unsupported capabilities is excellent. The chosen capabilities (SHA-256, AES, POSTPKIOperation) represent secure, modern choices for SCEP implementation.

Comment thread ee/server/service/hostidscep/scep.go Outdated
Comment thread ee/server/service/hostidscep/scep.go Outdated
@codecov

codecov Bot commented Jul 7, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 76.06635% with 101 lines in your changes missing coverage. Please review.

Project coverage is 64.15%. Comparing base (ab67979) to head (d8a11fa).
Report is 67 commits behind head on main.

Files with missing lines Patch % Lines
ee/server/service/hostidentity/scep.go 70.94% 24 Missing and 10 partials ⚠️
ee/server/service/hostidentity/depot/depot.go 69.23% 16 Missing and 8 partials ⚠️
cmd/fleet/serve.go 0.00% 11 Missing ⚠️
ee/server/service/hostidentity/config.go 71.87% 6 Missing and 3 partials ⚠️
server/mdm/scep/depot/fleet.go 57.14% 6 Missing and 3 partials ⚠️
...les/20250707095725_HostIdentitySCEPCertificates.go 80.00% 6 Missing and 2 partials ⚠️
.../mysql/common_mysql/testing_utils/testing_utils.go 76.92% 2 Missing and 1 partial ⚠️
server/datastore/mysql/host_identity_scep.go 75.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #30589      +/-   ##
==========================================
+ Coverage   64.11%   64.15%   +0.03%     
==========================================
  Files        1878     1886       +8     
  Lines      184499   184873     +374     
  Branches     5400     5400              
==========================================
+ Hits       118297   118603     +306     
- Misses      56897    56942      +45     
- Partials     9305     9328      +23     
Flag Coverage Δ
backend 65.14% <76.06%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
server/fleet/host_identity_certificates.go (1)

20-35: Redundant validation logic in UnmarshalPublicKey method.

The method performs two separate checks that could be consolidated:

  1. Line 21: guessCurve function checks raw byte length and returns error for unsupported lengths
  2. Line 26: Direct check for empty array and 0x04 prefix

The guessCurve function will already return an error for empty arrays, making the len(h.PublicKeyRaw) == 0 check redundant.

Consider consolidating the validation logic:

 func (h *HostIdentityCertificate) UnmarshalPublicKey() (*ecdsa.PublicKey, error) {
+	if len(h.PublicKeyRaw) == 0 || h.PublicKeyRaw[0] != 4 {
+		return nil, errors.New("unsupported EC point format")
+	}
+
 	curve, err := guessCurve(h.PublicKeyRaw)
 	if err != nil {
 		return nil, err
 	}
 
-	if len(h.PublicKeyRaw) == 0 || h.PublicKeyRaw[0] != 4 { // 0x04 means this is the raw representation
-		return nil, errors.New("unsupported EC point format")
-	}
-
 	byteLen := (len(h.PublicKeyRaw) - 1) / 2
 	x := new(big.Int).SetBytes(h.PublicKeyRaw[1 : 1+byteLen])
 	y := new(big.Int).SetBytes(h.PublicKeyRaw[1+byteLen:])
ee/server/integrationtest/hostidscep/hostidscep_test.go (2)

42-50: Consider adding P521 curve test for comprehensive coverage.

The test covers P256 and P384 curves but misses P521, which is also a standard NIST curve commonly used in certificate generation.

 func testGetCert(t *testing.T, s *Suite) {
 	t.Run("ECC P256", func(t *testing.T) {
 		testGetCertWithCurve(t, s, elliptic.P256())
 	})
 
 	t.Run("ECC P384", func(t *testing.T) {
 		testGetCertWithCurve(t, s, elliptic.P384())
 	})
+
+	t.Run("ECC P521", func(t *testing.T) {
+		testGetCertWithCurve(t, s, elliptic.P521())
+	})
 }

87-88: Consider using a stronger RSA key size for enhanced security.

While 2048-bit RSA is currently the minimum recommended size, using 3072 or 4096 bits would provide better security margins for the future.

 	// Create temporary RSA key for SCEP envelope (required by SCEP protocol)
-	tempRSAKey, err := rsa.GenerateKey(rand.Reader, 2048)
+	tempRSAKey, err := rsa.GenerateKey(rand.Reader, 3072)
 	require.NoError(t, err)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8978165 and 8913d29.

📒 Files selected for processing (16)
  • cmd/fleet/serve.go (2 hunks)
  • ee/server/integrationtest/hostidscep/hostidscep_test.go (1 hunks)
  • ee/server/integrationtest/hostidscep/suite.go (1 hunks)
  • ee/server/service/hostidscep/config.go (1 hunks)
  • ee/server/service/hostidscep/scep.go (1 hunks)
  • server/datastore/mysql/common_mysql/testing_utils/testing_utils.go (2 hunks)
  • server/datastore/mysql/host_identity_scep.go (1 hunks)
  • server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (1 hunks)
  • server/datastore/mysql/mysql.go (1 hunks)
  • server/datastore/mysql/schema.sql (2 hunks)
  • server/fleet/datastore.go (1 hunks)
  • server/fleet/host_identity_certificates.go (1 hunks)
  • server/fleet/host_identity_certificates_test.go (1 hunks)
  • server/mock/datastore_mock.go (3 hunks)
  • server/service/integrationtest/suite.go (2 hunks)
  • server/service/testing_utils.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ee/server/service/hostidscep/scep.go
🧰 Additional context used
🧬 Code Graph Analysis (6)
server/fleet/datastore.go (1)
server/fleet/host_identity_certificates.go (1)
  • HostIdentityCertificate (12-18)
cmd/fleet/serve.go (1)
ee/server/service/hostidscep/scep.go (1)
  • RegisterSCEP (27-57)
server/service/testing_utils.go (1)
ee/server/service/hostidscep/scep.go (1)
  • RegisterSCEP (27-57)
server/service/integrationtest/suite.go (2)
server/datastore/mysql/testing_utils.go (1)
  • CreateMySQLDSWithOptions (394-396)
server/datastore/mysql/common_mysql/testing_utils/testing_utils.go (1)
  • DatastoreTestOptions (82-99)
server/fleet/host_identity_certificates_test.go (1)
server/fleet/host_identity_certificates.go (2)
  • CreateECDSAPublicKeyRaw (48-67)
  • HostIdentityCertificate (12-18)
server/mock/datastore_mock.go (2)
server/fleet/host_identity_certificates.go (1)
  • HostIdentityCertificate (12-18)
server/fleet/calendar.go (1)
  • Lock (59-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (33)
  • GitHub Check: publish
  • GitHub Check: test-go (service, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (vuln, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (vuln, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (scripts, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (main, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (service, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (mysql, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (mysql, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (fleetctl, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-core, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-mdm, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (main, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-enterprise, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-mdm, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (integration-core, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (fast, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (fleetctl, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (integration-enterprise, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: check-doc-gen
  • GitHub Check: test-packaging (macos-15)
  • GitHub Check: test-db-changes
  • GitHub Check: test-packaging (ubuntu-latest)
  • GitHub Check: lint (windows-latest)
  • GitHub Check: build-and-check
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: test-packaging (ubuntu-latest, remote)
  • GitHub Check: lint (ubuntu-latest)
  • GitHub Check: lint (macos-latest)
  • GitHub Check: test-preview (ubuntu-latest)
  • GitHub Check: test-packaging (ubuntu-latest, local)
  • GitHub Check: build-binaries
🔇 Additional comments (25)
server/fleet/datastore.go (1)

2206-2211: LGTM! Well-designed interface addition for Host Identity SCEP support.

This method addition follows established datastore patterns with clear documentation and appropriate type signatures. The integration with the broader Host Identity SCEP feature is well-structured and maintains consistency with existing certificate management interfaces.

server/service/testing_utils.go (3)

21-21: LGTM: Import correctly added for Host Identity SCEP functionality.

The import is properly placed and necessary for the new SCEP service registration.


367-367: LGTM: New storage field follows established patterns.

The HostIdentitySCEPStorage field is consistent with other storage options in the struct and uses the appropriate scep_depot.Depot type.


475-477: LGTM: Conditional SCEP service registration follows established patterns.

The implementation correctly:

  • Uses conditional registration only when storage is provided
  • Passes the expected parameters (mux, storage, datastore, logger) to hostidscep.RegisterSCEP
  • Follows the same pattern as other conditional service registrations in this function
server/datastore/mysql/mysql.go (2)

192-196: LGTM: New Host Identity SCEP depot method is well-implemented.

The NewHostIdentitySCEPDepot method:

  • Follows the same pattern as the existing NewSCEPDepot method
  • Appropriately takes an additional logger parameter for specialized logging needs
  • Returns the correct interface type
  • Properly delegates to the underlying implementation function

186-190: No remaining references to NewMDMAppleSCEPDepot.
A repository-wide search confirmed zero occurrences of the old method name and all callers now use NewSCEPDepot. The rename is safe to merge.

cmd/fleet/serve.go (2)

28-28: Import addition looks good.

The import is correctly added and aligns with the new Host Identity SCEP feature implementation.


1197-1209: Well-structured conditional feature activation.

The Host Identity SCEP setup follows the established pattern for premium features:

  • Properly gated behind premium license check
  • Conditional activation based on private key configuration
  • Appropriate error handling with initFatal
  • Helpful warning message when prerequisites aren't met
  • Consistent with existing SCIM and SCEP proxy registration patterns

The security consideration of requiring a private key before enabling certificate-related functionality is appropriate.

ee/server/service/hostidscep/config.go (1)

12-50: Robust and secure asset initialization implementation.

The initAssets function demonstrates several good practices:

  1. Idempotent design: Checks for existing assets before generating new ones, preventing unnecessary regeneration
  2. Proper error handling: Uses error wrapping with context for debugging
  3. Security: Stores assets as encrypted MDM config assets in the database
  4. Established patterns: Uses the same asset management approach as other MDM components

The logic correctly handles the "not found" case for first-time asset generation while properly surfacing other database errors.

server/service/integrationtest/suite.go (2)

10-10: Import addition supports enhanced test infrastructure.

The testing_utils import enables the improved datastore creation with explicit test naming options.


57-59: Improved test isolation through explicit naming.

The change from CreateMySQLDS to CreateMySQLDSWithOptions with UniqueTestName provides better test isolation by allowing explicit control over test database naming. This prevents potential conflicts between concurrent tests and supports the new Host Identity SCEP integration test requirements.

server/datastore/mysql/common_mysql/testing_utils/testing_utils.go (2)

98-98: Enhanced test configuration with explicit naming option.

The addition of UniqueTestName field provides flexibility for test setups that require explicit control over database naming while maintaining backwards compatibility.


187-201: Well-implemented fallback logic for test naming.

The logic correctly prioritizes explicit UniqueTestName when provided, falling back to the existing runtime-derived naming approach. This maintains full backwards compatibility while enabling better test isolation for scenarios like the new Host Identity SCEP integration tests.

ee/server/integrationtest/hostidscep/suite.go (1)

15-51: Comprehensive integration test suite setup.

The Suite struct and SetUpSuite function provide a robust foundation for Host Identity SCEP integration testing:

  1. Proper licensing: Correctly sets up premium license tier for the feature
  2. Complete infrastructure: Creates MySQL datastore, SCEP depot, and test server with all dependencies
  3. Established patterns: Follows the same structure as other integration test suites in the codebase
  4. Test isolation: Uses unique test naming to prevent conflicts
  5. Authentication setup: Configures admin token for test execution

The setup ensures the full Host Identity SCEP flow can be tested end-to-end with proper isolation and dependencies.

server/mock/datastore_mock.go (3)

1415-1415: LGTM: Function type declaration follows established patterns.

The function type declaration is correctly implemented with appropriate parameter types that match the SerialNumber field type from the HostIdentityCertificate struct.


3503-3504: LGTM: Struct fields follow established naming conventions.

The new fields are properly named and positioned, following the consistent pattern used throughout the mock datastore for tracking mock function invocations.


8374-8379: LGTM: Method implementation follows standard mock pattern.

The method correctly implements the standard mock pattern with proper mutex handling for thread safety and invocation tracking. The implementation is consistent with other mock methods in the file.

server/fleet/host_identity_certificates_test.go (1)

1-122: Excellent comprehensive test coverage for ECDSA public key handling.

The test suite provides thorough coverage of both successful operations and error conditions for the HostIdentityCertificate public key functionality. The tests are well-structured with clear naming conventions and appropriate use of helper functions to avoid duplication.

Key strengths:

  • Tests both supported curves (P256, P384) and unsupported curve (P521)
  • Validates proper error handling for various malformed inputs
  • Uses realistic key generation for authentic test scenarios
  • Helper function testUnmarshalPublicKeyWithCurve promotes code reuse
server/fleet/host_identity_certificates.go (3)

12-18: Well-designed struct for host identity certificate storage.

The HostIdentityCertificate struct is appropriately designed with database tags and includes all necessary fields for certificate management including serial number, common name, host association, validity period, and raw public key storage.


37-46: Efficient curve detection based on byte length.

The guessCurve function provides a clean mapping from raw byte lengths to elliptic curves, supporting the standard uncompressed point format lengths for P256 and P384.


48-67: Robust ECDSA public key encoding with proper padding.

The CreateECDSAPublicKeyRaw function correctly handles the conversion from ECDSA public keys to raw byte format with appropriate coordinate padding using FillBytes() to ensure consistent byte lengths.

server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (3)

12-24: Well-designed serial number table with appropriate CA reservation.

The host_identity_scep_serials table design is solid with auto-increment starting at 2 to reserve serial number 1 for the CA certificate, which follows SCEP best practices.


26-48: Comprehensive certificate storage table with proper constraints.

The host_identity_scep_certificates table design includes all necessary fields for certificate management:

  • Proper foreign key relationship to serials table
  • Efficient indexes on name and host_id for lookup and revocation operations
  • Appropriate data types for certificate storage
  • Check constraint to validate PEM format integrity

The public_key_raw VARBINARY(100) field size accommodates both P256 (65 bytes) and P384 (97 bytes) public keys with room for future expansion.


53-66: Proper rollback implementation respecting foreign key constraints.

The Down function correctly drops tables in reverse order to respect foreign key constraints, ensuring clean migration rollback.

server/datastore/mysql/schema.sql (1)

521-525: Serial table LGTM, tiny nit

Table definition is solid. If you rely on reproducible schema dumps, explicitly setting AUTO_INCREMENT=1 (as done in a few other tables) keeps tools quiet.

Comment thread server/datastore/mysql/schema.sql
Comment thread server/datastore/mysql/host_identity_scep.go Outdated
@coderabbitai

coderabbitai Bot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (9)
server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (1)

53-55: Empty Down function - consider adding implementation

The Down function is currently empty, which means the migration cannot be rolled back. While this might be intentional for safety reasons, consider whether rollback capability would be useful for development or emergency scenarios.

If rollback capability is desired, consider implementing:

 func Down_20250707095725(tx *sql.Tx) error {
-	return nil
+	// Drop tables in reverse order to handle foreign key constraints
+	if _, err := tx.Exec("DROP TABLE IF EXISTS host_identity_scep_certificates"); err != nil {
+		return fmt.Errorf("failed to drop host_identity_scep_certificates table: %w", err)
+	}
+	if _, err := tx.Exec("DROP TABLE IF EXISTS host_identity_scep_serials"); err != nil {
+		return fmt.Errorf("failed to drop host_identity_scep_serials table: %w", err)
+	}
+	return nil
 }
ee/server/service/hostidentity/depot/depot.go (2)

58-69: Add comment to clarify auto-increment behavior.

The empty VALUES clause relies on MySQL's auto-increment behavior. Consider adding a comment to make this explicit.

 // Serial allocates and returns a new (increasing) serial number.
 func (d *HostIdentitySCEPDepot) Serial() (*big.Int, error) {
+	// Insert an empty row to generate a new auto-incremented serial number
 	result, err := d.db.Exec(`INSERT INTO host_identity_scep_serials () VALUES ();`)

71-75: Document the stub implementation more clearly.

This method always returns false regardless of parameters. If callers depend on this behavior, it could lead to unexpected results. Consider adding a more explicit comment or returning an "not implemented" error.

 // HasCN returns whether the given certificate exists in the depot.
 func (d *HostIdentitySCEPDepot) HasCN(cn string, allowTime int, cert *x509.Certificate, revokeOldCertificate bool) (bool, error) {
-	// Not used right now. May be used for renewal in the future.
+	// TODO: Not implemented. Always returns false.
+	// This will be implemented when certificate renewal is supported.
 	return false, nil
 }
ee/server/service/hostidentity/scep.go (3)

55-59: Track missing monitoring and error reporting.

The comment indicates that APM/OpenTel monitoring and error reporting to Sentry/Redis are missing. This should be tracked properly.

Would you like me to create an issue to track the implementation of proper monitoring and error reporting for the SCEP server?


132-135: Consider more specific validation for PKIOperation data.

While checking for empty data is good, consider validating minimum size requirements for a valid SCEP message.

 func (svc *service) PKIOperation(ctx context.Context, data []byte) ([]byte, error) {
-	if len(data) == 0 {
-		return nil, &fleet.BadRequestError{Message: "missing data for PKIOperation"}
+	// Minimum size for a valid SCEP message is typically larger than a few bytes
+	const minSCEPMessageSize = 100 // Adjust based on actual SCEP message requirements
+	if len(data) < minSCEPMessageSize {
+		return nil, &fleet.BadRequestError{Message: "invalid or missing data for PKIOperation"}
 	}

155-158: Provide more specific error message.

When the signer returns nil certificate without error, the generic error message could be more descriptive.

 	crt, err := svc.signer.SignCSRContext(ctx, msg.CSRReqMessage)
 	if err == nil && crt == nil {
-		err = errors.New("no signed certificate")
+		err = errors.New("signer returned nil certificate without error")
 	}
ee/server/integrationtest/hostidscep/hostidscep_test.go (3)

99-100: Extract magic numbers to test constants.

RSA key size and other values are hardcoded throughout the tests.

Add these constants at the package level:

const (
    testRSAKeySize = 2048
    testCertValidityDays = 365
)

Then update the usages:

-	tempRSAKey, err := rsa.GenerateKey(rand.Reader, 2048)
+	tempRSAKey, err := rsa.GenerateKey(rand.Reader, testRSAKeySize)

Also applies to: 272-273, 295-296


162-166: Add more specific assertion messages.

The assertions could benefit from more descriptive error messages to aid debugging.

-	assert.Equal(t, x509.ECDSA, cert.PublicKeyAlgorithm)
+	assert.Equal(t, x509.ECDSA, cert.PublicKeyAlgorithm, "Certificate should use ECDSA public key algorithm")
 	certPubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
 	require.True(t, ok, "Certificate should contain ECC public key")
-	assert.True(t, eccPrivateKey.PublicKey.Equal(certPubKey), "Certificate public key should match our ECC private key")
+	assert.True(t, eccPrivateKey.PublicKey.Equal(certPubKey), "Certificate public key should match the CSR's ECC public key")

342-343: Remove redundant assertion.

The second assertion is redundant as it's just the negation of the first.

 	// Verify failure response
 	assert.Equal(t, scep.FAILURE, pkiMsgResp.PKIStatus, "SCEP request should fail")
-	assert.NotEqual(t, scep.SUCCESS, pkiMsgResp.PKIStatus, "SCEP request should not succeed")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8913d29 and bbf16b6.

📒 Files selected for processing (15)
  • Makefile (1 hunks)
  • cmd/fleet/serve.go (2 hunks)
  • ee/server/integrationtest/hostidscep/hostidscep_test.go (1 hunks)
  • ee/server/service/hostidentity/config.go (1 hunks)
  • ee/server/service/hostidentity/depot/depot.go (1 hunks)
  • ee/server/service/hostidentity/scep.go (1 hunks)
  • ee/server/service/hostidentity/types/host_identity_certificates.go (1 hunks)
  • ee/server/service/hostidentity/types/host_identity_certificates_test.go (1 hunks)
  • server/cron/calendar_cron_test.go (0 hunks)
  • server/datastore/mysql/host_identity_scep.go (1 hunks)
  • server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (1 hunks)
  • server/datastore/mysql/mysql.go (2 hunks)
  • server/fleet/datastore.go (2 hunks)
  • server/mock/datastore_mock.go (4 hunks)
  • server/service/testing_utils.go (3 hunks)
💤 Files with no reviewable changes (1)
  • server/cron/calendar_cron_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • server/service/testing_utils.go
  • server/datastore/mysql/host_identity_scep.go
  • cmd/fleet/serve.go
  • server/datastore/mysql/mysql.go
  • server/fleet/datastore.go
  • server/mock/datastore_mock.go
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
ee/server/service/hostidentity/types/host_identity_certificates_test.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
ee/server/service/hostidentity/types/host_identity_certificates.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
ee/server/integrationtest/hostidscep/hostidscep_test.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
🧬 Code Graph Analysis (1)
ee/server/service/hostidentity/types/host_identity_certificates.go (1)
server/datastore/mysql/mysql.go (1)
  • New (222-275)
🪛 GitHub Actions: CodeQL
Makefile

[error] 191-191: Build failed during 'make fleet' command: build constraints exclude all Go files in 'server/bindata' directory.

🔇 Additional comments (10)
Makefile (1)

298-298: LGTM - Proper integration of new package into test suite

The addition of the new hostidentity/types package to the fast test suite is appropriate and ensures the unit tests for the new Host Identity SCEP functionality are run efficiently in CI.

ee/server/service/hostidentity/config.go (1)

12-50: LGTM - Well-structured asset initialization function

The initAssets function is well-implemented with proper error handling and clear logic flow. The function appropriately:

  1. Checks for existing assets before generating new ones
  2. Handles not-found errors gracefully for first-time initialization
  3. Generates new SCEP CA certificate and key when needed
  4. Uses the new generic certificate encoding functions
  5. Stores assets securely with proper error wrapping

The use of context.Background() is acceptable for initialization tasks, and the function being unexported is appropriate for internal use.

ee/server/service/hostidentity/types/host_identity_certificates_test.go (2)

13-97: Excellent test coverage for public key handling

The test suite comprehensively covers the UnmarshalPublicKey functionality with:

  1. Positive cases: Both supported curves (P256, P384) are tested
  2. Error conditions: Unsupported curves, invalid formats, empty data, wrong lengths
  3. Edge cases: Missing 0x04 prefix, wrong prefix values
  4. Proper assertions: Verifies both error conditions and successful key reconstruction

The use of a helper function testUnmarshalPublicKeyWithCurve for testing supported curves reduces code duplication and ensures consistent testing across different curve types.


99-122: Good test helper design with thorough verification

The testUnmarshalPublicKeyWithCurve helper function properly:

  1. Generates test keys with the specified curve
  2. Converts to raw format and back
  3. Verifies all key properties match (curve, X/Y coordinates)
  4. Uses both Cmp and Equal methods for comprehensive validation

The verification approach is thorough and ensures the round-trip conversion maintains key integrity.

ee/server/service/hostidentity/types/host_identity_certificates.go (4)

12-18: Well-designed struct with appropriate database tags

The HostIdentityCertificate struct is well-designed with:

  1. Clear field mapping: Database tags correctly map to expected column names
  2. Appropriate types: Uses uint64 for serial numbers and *uint for nullable host_id
  3. Raw key storage: PublicKeyRaw field stores the uncompressed EC point format

The struct design aligns with the database schema and provides the necessary fields for certificate management.


20-35: Robust public key unmarshaling with proper validation

The UnmarshalPublicKey method is well-implemented:

  1. Format validation: Correctly checks for 0x04 prefix indicating uncompressed format
  2. Curve detection: Uses key length to determine the appropriate elliptic curve
  3. Coordinate extraction: Properly splits the raw bytes into X and Y coordinates
  4. Error handling: Returns descriptive errors for invalid formats

The implementation follows standard EC public key parsing practices and handles edge cases appropriately.


37-46: Simple and effective curve detection logic

The guessCurve function correctly identifies curves based on raw key length:

  • P256: 65 bytes (0x04 + 32 + 32)
  • P384: 97 bytes (0x04 + 48 + 48)

The logic is straightforward and provides clear error messages for unsupported key lengths.


48-67: Proper raw key creation with coordinate padding

The CreateECDSAPublicKeyRaw function correctly:

  1. Validates curves: Only supports P256 and P384 as intended
  2. Pads coordinates: Uses FillBytes to ensure proper padding to expected size
  3. Adds prefix: Correctly prefixes with 0x04 for uncompressed format
  4. Error handling: Returns descriptive errors for unsupported curves

The implementation ensures consistent raw key format across the system.

server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (1)

12-51: Well-designed database schema with proper constraints

The migration creates a robust schema for Host Identity SCEP certificates:

Strengths:

  1. Proper table ordering: Creates host_identity_scep_serials first to satisfy foreign key constraints
  2. Smart serial management: AUTO_INCREMENT=2 reserves serial 1 for CA certificate
  3. Appropriate indexing: Indexes on name and host_id for efficient lookups and revocation
  4. Data integrity: Foreign key constraints and PEM format validation via check constraint
  5. Good data types: Uses appropriate MySQL types with proper charset/collation

Schema design choices (per retrieved learnings, these are intentional):

  • VARBINARY(100) for public_key_raw storage
  • Nullable host_id without foreign key constraint
  • DATETIME instead of DATETIME(6) for validity timestamps
ee/server/service/hostidentity/depot/depot.go (1)

31-41: LGTM!

The constructor properly validates the database connection before returning the depot instance.

Comment thread ee/server/service/hostidentity/depot/depot.go
Comment thread ee/server/service/hostidentity/depot/depot.go
Comment thread ee/server/service/hostidentity/depot/depot.go Outdated
Comment thread ee/server/service/hostidentity/depot/depot.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (4)
ee/server/service/hostidentity/depot/depot.go (4)

104-119: Security concern: Shared challenge allows certificate revocation.


108-111: Use the provided context instead of context.Background().

Also applies to: 120-124


82-82: Extract magic number to a constant.


115-115: Handle the error from RowsAffected().

🧹 Nitpick comments (6)
server/service/mdm.go (1)

213-215: EncodePrivateKeyPEM is RSA-only – consider future-proofing

certificate.EncodePrivateKeyPEM accepts *rsa.PrivateKey; if we ever migrate SCEP/MDM keys to ECC (P-256/P-384) this call will not compile.

Optional improvement:

- func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
+ func EncodePrivateKeyPEM(key crypto.PrivateKey) []byte {
+     switch k := key.(type) {
+     case *rsa.PrivateKey:
+         return pem.EncodeToMemory(&pem.Block{
+             Type:  "RSA PRIVATE KEY",
+             Bytes: x509.MarshalPKCS1PrivateKey(k),
+         })
+     case *ecdsa.PrivateKey:
+         b, _ := x509.MarshalECPrivateKey(k)
+         return pem.EncodeToMemory(&pem.Block{
+             Type:  "EC PRIVATE KEY",
+             Bytes: b,
+         })
+     default:
+         return nil
+     }
 }

This keeps callers unchanged and removes the RSA assumption.

server/service/integrationtest/suite.go (1)

57-59: Nice isolation of test databases

Creating the datastore with UniqueTestName helps parallel test runs avoid collisions. One nit: if callers pass an empty uniqueTestName, the DB name becomes an empty suffix. Consider auto-generating a UUID when the string is blank to keep the invariant that each suite gets its own DB.

ee/server/integrationtest/hostidscep/hostidscep_test.go (3)

24-24: Consider using a more descriptive constant name.

While the constant is fine for tests, consider using a more descriptive name like testEnrollmentSecret to make it clearer that this is test data.

-const enrollmentSecret = "test_secret"
+const testEnrollmentSecret = "test_secret"

98-125: Verify the necessity of temporary RSA key creation for each test.

While the temporary RSA key is required by the SCEP protocol for envelope encryption, consider extracting this logic into a helper function to reduce code duplication between success and failure tests.

// Helper function to create temporary RSA key and certificate for SCEP envelope
func createTempRSAKeyAndCert(t *testing.T, commonName string) (*rsa.PrivateKey, *x509.Certificate) {
    tempRSAKey, err := rsa.GenerateKey(rand.Reader, 2048)
    require.NoError(t, err)
    
    deviceCertTemplate := x509.Certificate{
        Subject: pkix.Name{
            CommonName: commonName,
        },
        NotBefore:             time.Now(),
        NotAfter:              time.Now().Add(365 * 24 * time.Hour),
        KeyUsage:              KeyUsageKeyEncryption | KeyUsageDigitalSignature,
        ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
        BasicConstraintsValid: true,
    }
    
    deviceCertDerBytes, err := x509.CreateCertificate(
        rand.Reader,
        &deviceCertTemplate,
        &deviceCertTemplate,
        &tempRSAKey.PublicKey,
        tempRSAKey,
    )
    require.NoError(t, err)
    
    deviceCert, err := x509.ParseCertificate(deviceCertDerBytes)
    require.NoError(t, err)
    
    return tempRSAKey, deviceCert
}

272-276: Consider adding a comment about RSA key usage in failure tests.

While the test correctly uses RSA keys to test non-ECC algorithm rejection, adding a comment would clarify that this is intentional for testing the server's algorithm validation.

     } else {
-        // Create RSA private key (should fail)
+        // Create RSA private key to test non-ECC algorithm rejection (should fail)
         rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
         require.NoError(t, err)
         privateKey = rsaKey
         sigAlg = x509.SHA256WithRSA
     }
server/datastore/mysql/schema.sql (1)

501-517: Nit: misleading index prefix idx_host_id_scep_name.

The prefix idx_host_id_… implies that host_id is part of the indexed columns, yet the index only covers name. This can be confusing when debugging execution plans later on.

-  KEY `idx_host_id_scep_name` (`name`),
+  -- keep naming consistent with indexed columns
+  KEY `idx_scep_name` (`name`),

Purely cosmetic, no functional impact.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0609b9b and bbf16b6.

📒 Files selected for processing (27)
  • Makefile (1 hunks)
  • cmd/fleet/serve.go (2 hunks)
  • ee/server/integrationtest/hostidscep/hostidscep_test.go (1 hunks)
  • ee/server/integrationtest/hostidscep/suite.go (1 hunks)
  • ee/server/service/hostidentity/config.go (1 hunks)
  • ee/server/service/hostidentity/depot/depot.go (1 hunks)
  • ee/server/service/hostidentity/scep.go (1 hunks)
  • ee/server/service/hostidentity/types/host_identity_certificates.go (1 hunks)
  • ee/server/service/hostidentity/types/host_identity_certificates_test.go (1 hunks)
  • pkg/certificate/certificate.go (2 hunks)
  • server/cron/calendar_cron_test.go (0 hunks)
  • server/datastore/mysql/common_mysql/testing_utils/testing_utils.go (2 hunks)
  • server/datastore/mysql/host_identity_scep.go (1 hunks)
  • server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (1 hunks)
  • server/datastore/mysql/mysql.go (2 hunks)
  • server/datastore/mysql/scep.go (2 hunks)
  • server/datastore/mysql/schema.sql (2 hunks)
  • server/datastore/mysql/wstep.go (2 hunks)
  • server/fleet/datastore.go (2 hunks)
  • server/fleet/mdm.go (1 hunks)
  • server/mdm/apple/cert.go (1 hunks)
  • server/mdm/apple/util.go (0 hunks)
  • server/mdm/scep/depot/fleet.go (1 hunks)
  • server/mock/datastore_mock.go (4 hunks)
  • server/service/integrationtest/suite.go (2 hunks)
  • server/service/mdm.go (3 hunks)
  • server/service/testing_utils.go (3 hunks)
💤 Files with no reviewable changes (2)
  • server/cron/calendar_cron_test.go
  • server/mdm/apple/util.go
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
ee/server/service/hostidentity/types/host_identity_certificates_test.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
server/datastore/mysql/migrations/tables/20250707095725_HostIdentitySCEPCertificates.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
server/datastore/mysql/host_identity_scep.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
ee/server/integrationtest/hostidscep/hostidscep_test.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
ee/server/service/hostidentity/types/host_identity_certificates.go (1)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
server/datastore/mysql/schema.sql (1)

undefined

<retrieved_learning>
Learnt from: getvictor
PR: #30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
</retrieved_learning>

🧬 Code Graph Analysis (11)
server/datastore/mysql/scep.go (1)
pkg/certificate/certificate.go (1)
  • EncodeCertPEM (244-250)
server/fleet/datastore.go (1)
ee/server/service/hostidentity/types/host_identity_certificates.go (1)
  • HostIdentityCertificate (12-18)
server/mock/datastore_mock.go (2)
ee/server/service/hostidentity/types/host_identity_certificates.go (1)
  • HostIdentityCertificate (12-18)
server/fleet/calendar.go (1)
  • Lock (59-77)
server/mdm/apple/cert.go (1)
server/mdm/scep/depot/fleet.go (1)
  • NewSCEPCACertKey (11-33)
server/datastore/mysql/wstep.go (1)
pkg/certificate/certificate.go (1)
  • EncodeCertPEM (244-250)
cmd/fleet/serve.go (2)
ee/server/service/hostidentity/depot/depot.go (1)
  • NewHostIdentitySCEPDepot (32-41)
ee/server/service/hostidentity/scep.go (1)
  • RegisterSCEP (27-63)
server/service/testing_utils.go (1)
ee/server/service/hostidentity/scep.go (1)
  • RegisterSCEP (27-63)
server/service/integrationtest/suite.go (2)
server/datastore/mysql/testing_utils.go (1)
  • CreateMySQLDSWithOptions (394-396)
server/datastore/mysql/common_mysql/testing_utils/testing_utils.go (1)
  • DatastoreTestOptions (82-99)
server/service/mdm.go (2)
pkg/certificate/certificate.go (2)
  • EncodeCertPEM (244-250)
  • EncodePrivateKeyPEM (253-259)
server/fleet/mdm.go (3)
  • MDMAssetCACert (734-734)
  • MDMAssetCAKey (737-737)
  • MDMAssetAPNSKey (740-740)
server/mdm/scep/depot/fleet.go (2)
server/mdm/apple/cert.go (1)
  • NewSCEPCACertKey (204-206)
pkg/certificate/certificate.go (1)
  • Certificate (132-136)
ee/server/service/hostidentity/types/host_identity_certificates.go (1)
server/datastore/mysql/mysql.go (1)
  • New (222-275)
🪛 GitHub Actions: CodeQL
Makefile

[error] 191-191: Make build failed: build constraints exclude all Go files in server/bindata directory.

🔇 Additional comments (43)
server/datastore/mysql/wstep.go (2)

12-12: LGTM: Import change aligns with certificate encoding centralization.

The replacement of the Apple MDM-specific import with the generic certificate package is part of a well-structured refactoring effort.


31-31: LGTM: Function call correctly updated to use centralized encoding.

The change from apple_mdm.EncodeCertPEM(crt) to certificate.EncodeCertPEM(crt) is consistent with the import change and maintains the same functionality while using the centralized certificate encoding utilities.

Makefile (1)

298-298: LGTM: Host identity types package properly added to fast test suite.

The addition of ./ee/server/service/hostidentity/types to FAST_PKGS_TO_TEST correctly integrates the new host identity SCEP functionality into the fast testing pipeline.

server/datastore/mysql/scep.go (2)

14-14: LGTM: Import change consistent with certificate encoding centralization.

The replacement of the Apple MDM import with the generic certificate package follows the same refactoring pattern applied across the codebase.


93-93: LGTM: Function call correctly updated to use centralized encoding.

The change from apple_mdm.EncodeCertPEM(crt) to certificate.EncodeCertPEM(crt) in the Put method maintains the same functionality while using the centralized certificate encoding utilities.

server/mdm/apple/cert.go (1)

205-205: LGTM: Function delegation improves architectural separation.

The delegation of SCEP CA certificate generation to depot.NewSCEPCACertKey() is a well-structured architectural improvement that centralizes certificate generation logic in the appropriate package while maintaining the same function signature and behavior.

server/fleet/mdm.go (1)

770-773: LGTM! Host identity CA asset constants are properly defined.

The new constants follow the established naming pattern and are consistent with the existing MDM asset constants. They provide clear, descriptive names for the host identity root CA certificate and key assets.

server/service/testing_utils.go (3)

21-21: LGTM! Import statement is correct.

The import of the hostidentity package is necessary for the new SCEP registration functionality.


367-367: LGTM! New test option field is properly integrated.

The HostIdentitySCEPStorage field follows the established pattern for optional test features and uses the appropriate type.


475-477: LGTM! Conditional SCEP registration follows established patterns.

The conditional registration logic is consistent with how other optional features are handled in this function. The nil check prevents potential panics, and the error handling using require.NoError is appropriate for test code.

cmd/fleet/serve.go (2)

28-28: Import addition looks good.

The import for the hostidentity package is correctly placed and follows the existing import organization pattern.


1197-1208: Host Identity SCEP integration is well-implemented.

The implementation follows the established pattern for premium features:

  • Properly checks for private key configuration
  • Creates the depot with appropriate error handling
  • Registers SCEP handlers conditionally
  • Provides clear warning message when private key is missing

The error handling is consistent with other premium feature initializations in the codebase.

pkg/certificate/certificate.go (2)

6-6: Import additions are appropriate.

The new imports for crypto/rsa and encoding/pem are correctly added to support the new PEM encoding functions.

Also applies to: 9-9


243-259: PEM encoding functions are well-implemented.

Both functions follow standard PEM encoding patterns:

  • EncodeCertPEM correctly creates a PEM block with "CERTIFICATE" type
  • EncodePrivateKeyPVM properly uses PKCS1 format for RSA private keys
  • Both functions use the appropriate pem.EncodeToMemory for encoding

The implementation is clean and follows established PEM encoding conventions.

ee/server/service/hostidentity/config.go (1)

1-51: Asset initialization function is well-implemented.

The initAssets function follows a solid pattern:

  • Checks for existing assets first to avoid unnecessary generation
  • Generates new SCEP CA certificate and key only when needed
  • Uses the new generic PEM encoding functions from the certificate package
  • Proper error handling with informative error messages
  • Follows the established pattern for asset initialization in the codebase

The logic correctly handles the case where assets don't exist (first-time setup) and avoids regenerating existing assets.

server/service/mdm.go (2)

24-25: Import aligns with cross-package reuse – looks good

Switching to the generic pkg/certificate helpers keeps the service layer agnostic of Apple-specific utilities. No issues.


2529-2531: Consistent use of new helpers – good

The PEM encoding in asset persistence now routes through the shared certificate package. Implementation stays functionally identical.

server/datastore/mysql/host_identity_scep.go (1)

12-24: LGTM! Well-implemented certificate retrieval method.

The implementation correctly:

  • Uses parameterized queries to prevent SQL injection
  • Includes proper validation checks for expiration (not_valid_after > NOW()) and revocation (revoked = 0)
  • Follows the established datastore pattern with appropriate error handling
  • Uses the reader connection for this read-only operation
server/datastore/mysql/mysql.go (3)

20-20: LGTM! Import added for host identity SCEP depot.


187-191: LGTM! Method renamed to reflect generic SCEP usage.

The rename from NewMDMAppleSCEPDepot to NewSCEPDepot better reflects the broader SCEP usage beyond Apple MDM.


193-197: LGTM! Host identity SCEP depot factory method properly implemented.

The method correctly delegates to the hostidentity depot package and follows the established pattern for depot factory methods.

server/mdm/scep/depot/fleet.go (2)

11-33: LGTM! Secure and well-implemented SCEP CA certificate generation.

The implementation correctly:

  • Uses 2048-bit RSA keys as required by Apple
  • Generates cryptographically secure random keys
  • Creates a self-signed CA certificate with appropriate 10-year validity
  • Includes proper error handling at each step
  • Returns both the parsed certificate and private key

35-41: LGTM! Proper RSA key generation with Apple-compliant size.

The 2048-bit key size is correctly enforced per Apple's requirements for CSR key sizes.

server/datastore/mysql/common_mysql/testing_utils/testing_utils.go (2)

98-98: LGTM! Useful addition for test isolation.

The UniqueTestName field allows explicit control over test database naming, improving test isolation and configurability.


187-201: LGTM! Well-implemented test name override logic.

The implementation correctly:

  • Uses explicit UniqueTestName when provided
  • Falls back to runtime-derived test names when not specified
  • Maintains backward compatibility
  • Preserves the existing name sanitization logic
ee/server/integrationtest/hostidscep/suite.go (1)

15-51: LGTM! Comprehensive integration test suite setup.

The test suite properly:

  • Embeds the existing BaseSuite for common functionality
  • Sets up premium license tier appropriate for host identity features
  • Initializes the host identity SCEP depot with proper logging
  • Configures the server with all necessary components
  • Sets up authentication token for API testing
  • Follows established integration test patterns
server/mock/datastore_mock.go (4)

14-14: LGTM: Import addition is correct.

The import for hostidentity types is necessary for the types.HostIdentityCertificate type used in the new mock method.


1416-1416: LGTM: Function type definition follows established patterns.

The function signature is well-designed with appropriate parameter and return types for certificate retrieval by serial number.


3504-3505: LGTM: Struct fields follow established mock patterns.

The function field and invocation tracking field are consistent with the patterns used throughout the mock datastore.


8375-8380: LGTM: Method implementation follows standard mock patterns.

The implementation correctly handles thread safety with mutex locking, tracks invocation, and delegates to the configured function. This is consistent with all other mock methods in the codebase.

ee/server/service/hostidentity/types/host_identity_certificates_test.go (1)

1-123: Comprehensive test coverage!

The test suite thoroughly covers both positive and negative test cases for ECDSA public key handling, including supported curves (P256, P384), error scenarios (unsupported curves, invalid formats, empty data), and proper validation of the marshaling/unmarshaling process.

ee/server/service/hostidentity/types/host_identity_certificates.go (1)

1-68: Well-structured ECDSA key handling implementation!

The implementation correctly handles ECDSA public keys for both P256 and P384 curves, with proper validation of the uncompressed point format (0x04 prefix) and appropriate coordinate extraction. The 100-byte limit for PublicKeyRaw appropriately accommodates P384 keys (97 bytes).

ee/server/service/hostidentity/scep.go (1)

1-187: Well-implemented SCEP service with proper security controls!

The implementation includes appropriate challenge-based enrollment validation, clear CA capability declarations, and proper error handling. The monitoring limitations are well-documented for future enhancement.

ee/server/integrationtest/hostidscep/hostidscep_test.go (8)

1-22: Well-structured imports and package declaration.

The imports are appropriate for the cryptographic operations and testing framework. The package structure follows Go conventions for integration tests.


26-44: Excellent test organization with proper cleanup.

The test structure follows best practices with:

  • Table-driven tests for multiple scenarios
  • Proper database cleanup between test runs
  • Clear separation of success and failure cases

The truncation of both host_identity_scep_serials and host_identity_scep_certificates tables ensures test isolation.


46-54: Good parametrization of ECC curve testing.

Testing both P256 and P384 curves ensures compatibility with common elliptic curve standards. This approach allows easy addition of other curves if needed.


56-184: Comprehensive SCEP certificate enrollment test with thorough validation.

This test covers the complete SCEP workflow:

  1. Enrollment secret setup
  2. ECC key generation
  3. CA certificate retrieval
  4. CSR creation and signing
  5. SCEP protocol envelope handling
  6. Certificate validation
  7. Database storage verification

The dual validation approach (SCEP response + database lookup) ensures data integrity throughout the process.


186-230: Comprehensive failure scenario testing.

The test cases cover important edge cases:

  • Authentication failures (empty/wrong password)
  • Input validation (CN length limits)
  • Algorithm restrictions (non-ECC rejection)

This ensures the SCEP service properly validates inputs and enforces security policies.


232-236: Well-defined test configuration structure.

The SCEPFailureConfig struct provides a clean way to parameterize failure tests. The fields are appropriate for testing different failure scenarios.


238-344: Thorough failure testing with proper error validation.

The failure test function properly validates that SCEP requests fail with the expected status. The test correctly expects scep.FAILURE status and verifies that the request does not succeed.


208-213: Verify SCEP CommonName length enforcement

I didn’t find any explicit 255-char limit check for the CommonName in the hostidentity SCEP implementation. The integration test in
• ee/server/integrationtest/hostidscep/hostidscep_test.go (testGetCertFailures “CN longer than 255 characters”)
assumes the server will reject a CN >255. Please confirm that the SCEP endpoint in ee/server/service/hostidentity (and its depot) enforces this limit—or add the check if it’s missing—to keep the test and implementation in sync.

server/datastore/mysql/schema.sql (2)

521-525: Table definition looks solid.

Primary key on serial, AUTO_INCREMENT starts at 2 to reserve the CA’s serial, charset and collation are consistent with the rest of the schema. No issues spotted.


1412-1414: No actionable feedback – AUTO_INCREMENT=401 and the new migration record keep the sequence in sync.

Comment thread server/fleet/datastore.go
Comment thread server/fleet/datastore.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ee/server/integrationtest/hostidentity/hostidscep_test.go (1)

56-158: Consider breaking down this function for better maintainability.

While the test logic is comprehensive and correct, this 100+ line function could benefit from being broken down into smaller helper functions for improved readability and maintainability.

Consider extracting logical sections into helper functions:

-func testGetCertWithCurve(t *testing.T, s *Suite, curve elliptic.Curve) {
-	ctx := t.Context()
-	// Create an enrollment secret
-	err := s.DS.ApplyEnrollSecrets(ctx, nil, []*fleet.EnrollSecret{
-		{
-			Secret: testEnrollmentSecret,
-		},
-	})
-	require.NoError(t, err)
+func testGetCertWithCurve(t *testing.T, s *Suite, curve elliptic.Curve) {
+	ctx := t.Context()
+	
+	// Setup
+	setupEnrollmentSecret(t, ctx, s.DS)
+	eccPrivateKey := generateECCKey(t, curve)
+	scepClient, caCerts := setupSCEPClient(t, ctx, s)
+	
+	// Create and send SCEP request
+	cert := performSCEPEnrollment(t, ctx, scepClient, caCerts, eccPrivateKey, curve)
+	
+	// Verify certificate
+	verifyCertificateProperties(t, cert, eccPrivateKey, curve)
+	verifyStoredCertificate(t, ctx, s.DS, cert, eccPrivateKey, curve)
+}
+
+func setupEnrollmentSecret(t *testing.T, ctx context.Context, ds fleet.Datastore) {
+	err := ds.ApplyEnrollSecrets(ctx, nil, []*fleet.EnrollSecret{
+		{Secret: testEnrollmentSecret},
+	})
+	require.NoError(t, err)
+}
+
+func generateECCKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
+	eccPrivateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
+	require.NoError(t, err)
+	return eccPrivateKey
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bbf16b6 and d8a11fa.

📒 Files selected for processing (4)
  • ee/server/integrationtest/hostidentity/hostidscep_test.go (1 hunks)
  • ee/server/integrationtest/hostidentity/suite.go (1 hunks)
  • ee/server/service/hostidentity/depot/depot.go (1 hunks)
  • ee/server/service/hostidentity/scep.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ee/server/service/hostidentity/scep.go
  • ee/server/service/hostidentity/depot/depot.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: ee/server/service/hostidentity/depot/depot.go:104-119
Timestamp: 2025-07-08T16:06:54.566Z
Learning: In ee/server/service/hostidentity/depot/depot.go, the security concern where shared challenges allow certificate revocation (lines 104-119) is a known issue that will be addressed in a later feature, not an immediate concern to fix.
ee/server/integrationtest/hostidentity/hostidscep_test.go (3)
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: ee/server/service/hostidentity/depot/depot.go:104-119
Timestamp: 2025-07-08T16:06:54.566Z
Learning: In ee/server/service/hostidentity/depot/depot.go, the security concern where shared challenges allow certificate revocation (lines 104-119) is a known issue that will be addressed in a later feature, not an immediate concern to fix.
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: ee/server/service/hostidentity/depot/depot.go:108-111
Timestamp: 2025-07-08T16:12:48.756Z
Learning: In ee/server/service/hostidentity/depot/depot.go, the SCEP depot interface methods like Put() do not accept context parameters, and the common_mysql.WithRetryTxx callback function type TxFn only receives a transaction parameter, not a context. Therefore, using context.Background() in tx.ExecContext calls within the transaction callback is the correct approach.
Learnt from: getvictor
PR: fleetdm/fleet#30589
File: server/datastore/mysql/schema.sql:501-517
Timestamp: 2025-07-07T22:21:15.721Z
Learning: In the host_identity_scep_certificates table schema, the VARBINARY(100) size for public_key_raw, the nullable host_id without a foreign key constraint, and the use of plain DATETIME instead of DATETIME(6) are intentional design decisions, not issues to be addressed.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (32)
  • GitHub Check: lint (ubuntu-latest)
  • GitHub Check: lint (macos-latest)
  • GitHub Check: lint (windows-latest)
  • GitHub Check: test-go (main, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (service, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (fleetctl, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-core, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (vuln, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-enterprise, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (scripts, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (fleetctl, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (vuln, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (main, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (integration-mdm, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (mysql, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (service, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (mysql, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-mdm, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go (integration-enterprise, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (fast, ubuntu-latest, mysql:8.0.36, false)
  • GitHub Check: test-go (integration-core, ubuntu-latest, mysql:9.3.0, false)
  • GitHub Check: test-go-nanomdm
  • GitHub Check: check-doc-gen
  • GitHub Check: build-binaries
  • GitHub Check: test-preview (ubuntu-latest)
  • GitHub Check: publish
  • GitHub Check: test-db-changes
  • GitHub Check: test-packaging (ubuntu-latest)
  • GitHub Check: test-packaging (macos-15)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Analyze (go)
  • GitHub Check: build-and-check
🔇 Additional comments (4)
ee/server/integrationtest/hostidentity/suite.go (1)

19-51: LGTM! Well-structured test suite setup.

The test suite properly initializes all required components for host identity SCEP integration testing, including the MySQL datastore, Fleet service with premium license, and the SCEP depot.

ee/server/integrationtest/hostidentity/hostidscep_test.go (3)

26-44: LGTM! Proper test setup with table cleanup.

The test structure ensures proper isolation between test runs by truncating the relevant tables.


160-189: LGTM! Well-implemented helper function.

The function correctly creates the RSA key and certificate required for SCEP protocol envelope encryption.


191-235: LGTM! Comprehensive failure test coverage.

The test cases properly cover important failure scenarios including authentication, input validation, and algorithm restrictions.

@lucasmrod

Copy link
Copy Markdown
Member

Merging as Victor is OOO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:ai Request AI PR review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TPM: New SCEP endpoint on server

2 participants