Skip to content

fix(policy): reject unencrypted private keys for modes 1/2#3072

Merged
strantalis merged 2 commits into
mainfrom
fix/reject-unencrypted-private-keys
Feb 13, 2026
Merged

fix(policy): reject unencrypted private keys for modes 1/2#3072
strantalis merged 2 commits into
mainfrom
fix/reject-unencrypted-private-keys

Conversation

@strantalis

Copy link
Copy Markdown
Member

Summary

  • add ocrypto.IsPEMOrDERPrivateKey to detect PEM/DER private keys
  • reject unencrypted private keys in KAS CreateKey/RotateKey for modes 1/2
  • add integration coverage for Create/Rotate; add ocrypto unit tests

Testing

  • gofumpt -w lib/ocrypto/key_material.go lib/ocrypto/key_material_test.go service/pkg/db/errors.go service/policy/db/key_access_server_registry.go service/integration/kas_registry_key_unencrypted_test.go
  • cd lib/ocrypto && golangci-lint run ./...
  • cd lib/ocrypto && go test ./...
  • cd service && go test ./policy/db

Notes

  • cd service && golangci-lint run ./policy/db ./integration fails due to existing funcorder/staticcheck findings in integration and deprecated usage (pre-existing).
  • cd service && go test ./integration -run Test_CreateKasKey_PEMPrivateKey_Fail failed due to Testcontainers/Docker socket (/Users/strantalis/.colima/default/docker.sock) not available in this environment.

Signed-off-by: strantalis <strantalis@virtru.com>
@github-actions github-actions Bot added comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:lib:ocrypto size/s labels Feb 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 185.740766ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 103.151857ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 365.572611ms
Throughput 273.54 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 39.043735897s
Average Latency 388.885081ms
Throughput 128.06 requests/second

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @strantalis, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the security posture of the Key Access Server by enforcing a policy against the use of unencrypted private keys for critical root key configurations. By introducing a dedicated utility for private key format detection and integrating it into the key creation and rotation workflows, the system now proactively prevents a common security vulnerability, ensuring that sensitive cryptographic material is always handled securely.

Highlights

  • Security Enhancement: Introduced a new validation step to reject unencrypted private keys during CreateKey and RotateKey operations within the Key Access Server (KAS) for CONFIG_ROOT_KEY and PROVIDER_ROOT_KEY modes, enhancing security by preventing the storage of sensitive keys in an unencrypted state.
  • New Cryptographic Utility: Added a new utility function, ocrypto.IsPEMOrDERPrivateKey, to reliably detect if a given byte array represents an unencrypted private key in either PEM or DER format.
  • Error Handling and Testing: Implemented a new error type, ErrUnencryptedPrivateKey, and added comprehensive unit tests for the new cryptographic utility, along with integration tests to ensure the KAS CreateKey and RotateKey functions correctly reject unencrypted private keys.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • lib/ocrypto/key_material.go
    • Added IsPEMOrDERPrivateKey function to identify unencrypted private keys in PEM or DER format.
    • Implemented logic to parse PEM blocks and check for 'PRIVATE KEY' type strings.
    • Included checks for DER-encoded PKCS8, PKCS1, and EC private keys using x509 package functions.
  • lib/ocrypto/key_material_test.go
    • Created TestIsPEMOrDERPrivateKey to validate the new key detection utility.
    • Added test cases for various PEM-encoded private keys (RSA, EC).
    • Included tests for PEM-encoded public keys and random byte sequences to ensure correct negative results.
    • Added a test case for DER-encoded private keys extracted from PEM.
  • service/integration/kas_registry_key_unencrypted_test.go
    • Added Test_CreateKasKey_PEMPrivateKey_Fail to verify that CreateKey requests with unencrypted PEM private keys are rejected.
    • Added Test_RotateKey_PEMPrivateKey_Fail to verify that RotateKey requests with unencrypted PEM private keys are rejected.
  • service/pkg/db/errors.go
    • Defined a new error variable ErrUnencryptedPrivateKey.
    • Defined a new string constant ErrorTextUnencryptedPrivateKey.
    • Updated the StatusifyError function to map ErrUnencryptedPrivateKey to a connect.CodeInvalidArgument.
  • service/policy/db/key_access_server_registry.go
    • Imported the new github.com/opentdf/platform/lib/ocrypto package.
    • Modified the CreateKey function to include validation for private keys when KeyMode is CONFIG_ROOT_KEY or PROVIDER_ROOT_KEY.
    • Added logic to decode the WrappedKey from base64 and check if it's an unencrypted private key using ocrypto.IsPEMOrDERPrivateKey.
    • Returned db.ErrUnencryptedPrivateKey if an unencrypted private key is detected during CreateKey.
Activity
  • Code formatted using gofumpt for lib/ocrypto/key_material.go, lib/ocrypto/key_material_test.go, service/pkg/db/errors.go, service/policy/db/key_access_server_registry.go, and service/integration/kas_registry_key_unencrypted_test.go.
  • Linting (golangci-lint) was run on lib/ocrypto.
  • Unit tests (go test) were executed for lib/ocrypto and service/policy/db.
  • Noted that golangci-lint for service/policy/db and service/integration failed due to pre-existing funcorder/staticcheck findings and deprecated usage.
  • Noted that an integration test (Test_CreateKasKey_PEMPrivateKey_Fail) failed due to Testcontainers/Docker socket not being available in the environment.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


A key, unencrypted, a secret laid bare, No lock on the door, no one to care. This code now stands guard, with purpose so true, To keep all your secrets, safe and brand new.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a security enhancement by rejecting unencrypted private keys for KAS key creation and rotation in modes 1 and 2. This is achieved by adding a new function ocrypto.IsPEMOrDERPrivateKey to detect PEM or DER formatted private keys. The changes include the new detection logic, its integration into the key creation workflow, and corresponding unit and integration tests to ensure correctness. Overall, the changes are well-implemented and improve the security posture of the service. I have one suggestion to improve code efficiency and readability.

Comment thread service/policy/db/key_access_server_registry.go
@github-actions

Copy link
Copy Markdown
Contributor

Signed-off-by: strantalis <strantalis@virtru.com>
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 202.137586ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 92.402023ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 358.633761ms
Throughput 278.84 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 39.578233023s
Average Latency 394.43985ms
Throughput 126.33 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

@c-r33d c-r33d 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.

@strantalis
strantalis marked this pull request as ready for review February 12, 2026 18:19
@strantalis
strantalis requested review from a team as code owners February 12, 2026 18:19
@strantalis
strantalis enabled auto-merge February 12, 2026 19:33
Comment thread lib/ocrypto/key_material.go
@dmihalcik-virtru
dmihalcik-virtru self-requested a review February 13, 2026 13:33
@strantalis
strantalis added this pull request to the merge queue Feb 13, 2026
Merged via the queue into main with commit e2dc6d8 Feb 13, 2026
39 checks passed
@strantalis
strantalis deleted the fix/reject-unencrypted-private-keys branch February 13, 2026 16:50
github-merge-queue Bot pushed a commit that referenced this pull request Feb 17, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.10.0](lib/ocrypto/v0.9.0...lib/ocrypto/v0.10.0)
(2026-02-13)


### Bug Fixes

* Go 1.25 ([#3053](#3053))
([65eb7c3](65eb7c3))
* **kas:** dont hardcode P-256 curve
([#3073](#3073))
([826d857](826d857))
* **policy:** reject unencrypted private keys for modes 1/2
([#3072](#3072))
([e2dc6d8](e2dc6d8))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: opentdf-automation[bot] <149537512+opentdf-automation[bot]@users.noreply.github.com>
github-merge-queue Bot pushed a commit that referenced this pull request Feb 18, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.13.0](service/v0.12.0...service/v0.13.0)
(2026-02-18)


### ⚠ BREAKING CHANGES

* **policy:** remove namespace certificate feature
([#3051](#3051))

### Features

* **authz:** add casbin roleprovider interface
([#3069](#3069))
([9d6b3f3](9d6b3f3))
* **core:** add interceptors to start options
([#3031](#3031))
([e0b4e93](e0b4e93))


### Bug Fixes

* **deps:** bump github.com/opentdf/platform/lib/fixtures from 0.4.0 to
0.5.0 in /service
([#3034](#3034))
([66b61b1](66b61b1))
* **deps:** bump github.com/opentdf/platform/lib/ocrypto from 0.9.0 to
0.10.0 in /service
([#3080](#3080))
([49582f0](49582f0))
* **deps:** bump github.com/opentdf/platform/protocol/go from 0.15.0 to
0.16.0 in /service
([#3083](#3083))
([a332f95](a332f95))
* **deps:** vulnerability fix in connect-rpc validate and ristretto
([#3065](#3065))
([8860fed](8860fed))
* Go 1.25 ([#3053](#3053))
([65eb7c3](65eb7c3))
* **kas:** dont hardcode P-256 curve
([#3073](#3073))
([826d857](826d857))
* **kas:** Fix EC P-521 typo
([#3075](#3075))
([abc088d](abc088d))
* **policy:** reject unencrypted private keys for modes 1/2
([#3072](#3072))
([e2dc6d8](e2dc6d8))


### Code Refactoring

* **policy:** remove namespace certificate feature
([#3051](#3051))
([48abb81](48abb81))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: opentdf-automation[bot] <149537512+opentdf-automation[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:db DB component comp:lib:ocrypto comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) size/s

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants