fix: EC fallback to PEM
Proposed Changes
This pull request improves the robustness of the ECPrivateKeyFromPem function in ec_key_pair.go by adding support for parsing EC private keys in both PKCS8 and traditional EC formats. If parsing as PKCS8 fails, the function now attempts to parse the key as an EC private key before returning an error.
Key improvement to private key parsing:
- Enhanced
ECPrivateKeyFromPemto try parsing the input as a traditional EC private key if PKCS8 parsing fails, improving compatibility with different PEM-encoded EC key formats.
Checklist
- [ ] I have added or updated unit tests
- [ ] I have added or updated integration tests (if appropriate)
- [ ] I have added or updated documentation
Testing Instructions
Summary of Changes
Hello @pflynn-virtru, I'm Gemini Code Assist[^1]! 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 enhances the ECPrivateKeyFromPem function's ability to handle various PEM-encoded EC private key formats. By implementing a fallback mechanism, the system becomes more resilient to different key encodings, ensuring broader compatibility and reducing potential parsing failures when dealing with elliptic curve private keys.
Highlights
-
EC Private Key Parsing Robustness: The
ECPrivateKeyFromPemfunction now attempts to parse EC private keys using the traditional EC format if parsing as PKCS8 fails, enhancing compatibility with various PEM-encoded key types. - Improved Error Handling: Error messages are more informative, providing details if parsing fails for both PKCS8 and traditional EC formats, aiding in debugging.
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 |
|---|
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 :thumbsup: and :thumbsdown: 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.
Key in PEM's embrace, PKCS8 first, then EC, Robust parse, secure.
[^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.
Benchmark results, click to expand
Benchmark authorization.GetDecisions Results:
| Metric | Value |
|---|---|
| Approved Decision Requests | 1000 |
| Denied Decision Requests | 0 |
| Total Time | 185.639664ms |
Benchmark authorization.v2.GetMultiResourceDecision Results:
| Metric | Value |
|---|---|
| Approved Decision Requests | 1000 |
| Denied Decision Requests | 0 |
| Total Time | 94.930089ms |
Standard Benchmark Metrics Skipped or Failed
Bulk Benchmark Results
| Metric | Value |
|---|---|
| Total Decrypts | 100 |
| Successful Decrypts | 100 |
| Failed Decrypts | 0 |
| Total Time | 347.553739ms |
| Throughput | 287.73 requests/second |
TDF3 Benchmark Results:
| Metric | Value |
|---|---|
| Total Requests | 5000 |
| Successful Requests | 5000 |
| Failed Requests | 0 |
| Concurrent Requests | 50 |
| Total Time | 36.872086693s |
| Average Latency | 366.947238ms |
| Throughput | 135.60 requests/second |
NANOTDF Benchmark Results:
| Metric | Value |
|---|---|
| Total Requests | 5000 |
| Successful Requests | 5000 |
| Failed Requests | 0 |
| Concurrent Requests | 50 |
| Total Time | 25.800826369s |
| Average Latency | 256.525756ms |
| Throughput | 193.79 requests/second |
The bug persists.
Reproduce with my codespace on this branch: https://symmetrical-funicular-gv6xqxx76r3v5rx.github.dev/
Run ./linux_startup to reset the platform and run hello_world.js to test the encrypt() function.
Update: Codespaces might be unshareable. Use this script in a codespace based on this branch to reproduce on a standardized environment:
cp opentdf-dev.yaml opentdf.yaml
./.github/scripts/init-temp-keys.sh
sudo cp ./keys/localhost.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates
# Kill existing containers and start fresh
docker ps -aq | xargs -r docker rm -f
docker compose up -d
sleep 5
read -p "Are the docker containers ready? Press Enter to continue..."
go run ./service provision keycloak
go run ./service provision fixtures
go run ./service start &
sleep 5
read -p "Is the go service ready? Press Enter to continue..."
git clone https://github.com/nibsbin/opentdf-basekey-bug.git
cd opentdf-basekey-bug
npm run dev
Error persists but new typescript workflow on this commit can full encrypt and decrypt document.
codespace@codespaces-a8536a:/workspaces/opentdf-demo-server/opentdf-basekey-bug$ npm install; npm run dev
up to date, audited 17 packages in 690ms
5 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
> [email protected] dev
> tsx hello_world.ts
✅ Authentication provider created
🔧 Creating OpenTDF client...
Development URL detected: [http://localhost:8080]
✅ Client created
📁 Using temp files:
Input: /tmp/opentdf-input.txt
Encrypted: /tmp/opentdf-encrypted.tdf
Decrypted: /tmp/opentdf-decrypted.txt
📝 Preparing sensitive data for encryption...
✅ Input file written: This is sensitive data that will be encrypted with OpenTDF!
🔒 Starting encryption...
📖 Reading input file for encryption...
📡 Calling client.encrypt...
Development URL detected: [http://localhost:8080]
NetworkError: [http://localhost:8080] [PublicKey] Invalid Platform Configuration: [http://localhost:8080] is missing BaseKey in WellKnownConfiguration
at fetchKasBasePubKey (/workspaces/opentdf-demo-server/opentdf-basekey-bug/node_modules/@opentdf/sdk/src/access/access-rpc.ts:173:11)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async fetchKasPubKey (/workspaces/opentdf-demo-server/opentdf-basekey-bug/node_modules/@opentdf/sdk/src/access.ts:173:12)
at async Promise.any (index 0)
at async <anonymous> (/workspaces/opentdf-demo-server/opentdf-basekey-bug/node_modules/@opentdf/sdk/tdf3/src/client/index.ts:473:30)
at async Promise.all (index 0)
at async Client.encrypt (/workspaces/opentdf-demo-server/opentdf-basekey-bug/node_modules/@opentdf/sdk/tdf3/src/client/index.ts:468:39)
at async OpenTDF.createZTDF (/workspaces/opentdf-demo-server/opentdf-basekey-bug/node_modules/@opentdf/sdk/src/opentdf.ts:384:23)
at async <anonymous> (/workspaces/opentdf-demo-server/opentdf-basekey-bug/hello_world.ts:62:11)
Development URL detected: [http://localhost:8080]
Mismatched wrapping key algorithm: [rsa:2048] is not requested type, [undefined]
💾 Saving encrypted data to temp file /tmp/opentdf-encrypted.tdf
✅ Data encrypted and saved to file!
🔓 Decrypting data...
Development URL detected: [http://localhost:8080/kas]
💾 Saving decrypted data to temp file...
✅ Data decrypted and saved to file!
📤 Decrypted content:
"This is sensitive data that will be encrypted with OpenTDF!"