ovh/kmip-go
GitHub: ovh/kmip-go
kmip-go是一个支持KMIP协议的Go语言库,用于实现密钥管理系统。
Stars: 37 | Forks: 10
# kmip-go
[](https://pkg.go.dev/github.com/ovh/kmip-go) [](https://raw.githubusercontent.com/ovh/kmip-go/master/LICENSE) [](https://github.com/ovh/kmip-go/actions/workflows/test.yaml) [](https://goreportcard.com/report/github.com/ovh/kmip-go)
Key Management Interoperability Protocol (KMIP) 的全面 Go 实现,支持 KMIP 版本 1.0 到 1.4。此库提供客户端和服务器实现,并全面支持加密操作、密钥生命周期管理和安全通信。
查看 [KMIP v1.4 协议规范](https://docs.oasis-open.org/kmip/spec/v1.4/os/kmip-spec-v1.4-os.pdf).
## 🚀 功能
- **全面 KMIP 协议支持**:实现 KMIP v1.0 到 v1.4 规范
- **完整的客户端库**:高级流畅的 API,全面支持操作
- **服务器实现**:生产就绪的 KMIP 服务器组件
- **多种编码格式**:二进制 TTLV、XML、JSON 和可读文本格式
- **可扩展**:易于声明用户定义的 KMIP 类型和扩展
- **全面的加密操作**:密钥生成、加密、解密、签名、验证
- **灵活的认证**:相互 TLS、用户名/密码、设备和基于证明的认证
- **TLS 安全**:内置 TLS 支持,具有客户端证书认证
- **HTTPS 传输**:可选的 KMIP-over-HTTPS,支持 TTLV、XML 或 JSON 传输格式(可选子包)
- **批处理操作**:支持在单个请求中批处理多个操作
- **中间件系统**:可扩展的中间件,用于日志记录、调试和自定义功能
- **与 Go 标准加密兼容**:实现 crypto.Signer 接口,并支持标准库中的加密密钥类型
- **生产就绪**:针对 [OVHcloud KMS](https://help.ovhcloud.com/csm/en-ie-kms-quick-start?id=kb_article_view&sysparm_article=KB0063362) 进行开发和测试
## 📚 目录
- [安装](#-installation)
- [快速入门](#-quick-start)
- [客户端 API](#-client-api)
- [服务器 API](#️-server-api)
- [高级功能](#-advanced-features)
- [认证](#-authentication)
- [示例](#-examples)
- [实现状态](#-implementation-status)
- [贡献](#️-contributing)
- [故障排除](#-troubleshooting)
- [开发](#️-development)
- [许可证](#-license)
- [支持](#-support)
- [致谢](#-acknowledgments)
## 📦 安装
```
go get github.com/ovh/kmip-go@latest
```
## 🏃 快速入门
```
package main
import (
"fmt"
"log"
"github.com/ovh/kmip-go"
"github.com/ovh/kmip-go/kmipclient"
)
func main() {
// Connect to KMIP server
client, err := kmipclient.Dial(
"your-kmip-server:5696",
kmipclient.WithClientCertFiles("cert.pem", "key.pem"),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Create an AES key
resp := client.Create().
AES(256, kmip.CryptographicUsageEncrypt|kmip.CryptographicUsageDecrypt).
WithName("my-encryption-key").
MustExec()
fmt.Printf("Created AES key: %s\n", resp.UniqueIdentifier)
// Activate the key
client.Activate(resp.UniqueIdentifier).MustExec()
// Encrypt some data
plaintext := []byte("Hello, KMIP!")
encrypted := client.Encrypt(resp.UniqueIdentifier).
WithCryptographicParameters(kmip.AES_GCM).
Data(plaintext).
MustExec()
fmt.Printf("Encrypted data length: %d bytes\n", len(encrypted.Data))
}
```
## 🔧 客户端 API
### 连接和配置
```
import (
"os"
"time"
"github.com/google/uuid"
"github.com/ovh/kmip-go"
"github.com/ovh/kmip-go/kmipclient"
"github.com/ovh/kmip-go/ttlv"
)
// Connect with comprehensive options
client, err := kmipclient.Dial(
"eu-west-rbx.okms.ovh.net:5696",
// TLS Configuration
kmipclient.WithRootCAFile("ca.pem"), // Custom CA certificate
kmipclient.WithClientCertFiles("cert.pem", "key.pem"), // Client certificates
kmipclient.WithClientCertPEM(certPEM, keyPEM), // Client certs from PEM data
kmipclient.WithServerName("kmip.example.com"), // Server name for TLS
kmipclient.WithTlsConfig(tlsConfig), // Custom TLS config
// Protocol Version Configuration
kmipclient.WithKmipVersions(kmip.V1_4, kmip.V1_3), // Supported versions
kmipclient.EnforceVersion(kmip.V1_4), // Enforce specific version
// Message size limit (default: 1 MB, < 0 disables)
kmipclient.WithMaxMessageSize(2 * 1024 * 1024), // 2 MB limit
// Middleware
kmipclient.WithMiddlewares(
kmipclient.CorrelationValueMiddleware(uuid.NewString),
kmipclient.DebugMiddleware(os.Stdout, ttlv.MarshalXML),
kmipclient.TimeoutMiddleware(30*time.Second),
),
)
```
### HTTP 传输
默认情况下,客户端使用 KMIP 的原生 TTLV-over-TLS 流协议。对于暴露 KMIP 的 HTTPS 服务器,可以通过 `kmipclient/kmiphttp` 子包选择 HTTP 传输。仅当使用 `kmiphttp` 时,才链接 `net/http`;仅调用者使用 `kmiphttp` 才承担这种成本。
```
import (
"github.com/ovh/kmip-go/kmipclient"
"github.com/ovh/kmip-go/kmipclient/kmiphttp"
)
```
请求通过 POST 发送到 `https://`;标准 TLS 选项保持不变。方案硬编码为 `https`:传递一个裸 `host:port`(没有 `http://` 或 `https://` 前缀),因为 HTTPS 是隐含的,并且方案前缀在 `Dial` 时刻被拒绝。
```
client, err := kmipclient.Dial(
"kms.example.com:5696",
kmiphttp.WithTransport("/kmip"),
kmipclient.WithClientCertFiles("cert.pem", "key.pem"),
)
```
默认的传输格式是二进制 TTLV;使用 `kmiphttp.WithWireFormat` 选择 XML 或 JSON:
```
client, err := kmipclient.Dial(
"kms.example.com:5696",
kmiphttp.WithTransport("/kmip",
kmiphttp.WithWireFormat(kmiphttp.WireJSON),
),
kmipclient.WithClientCertFiles("cert.pem", "key.pem"),
)
```
非 2xx 响应作为类型为 `*kmiphttp.Error` 的返回,包含 `StatusCode` 和有界 `Body` 摘录——使用 `errors.As` 而不是匹配错误字符串。请参阅 API 文档中的 `kmiphttp.WithHeader`(自定义头)和 `kmiphttp.WithClient`(提供自己的 `*http.Client`)。
### 密钥创建和管理
#### 对称密钥
```
// AES Keys
aes128 := client.Create().AES(128, kmip.CryptographicUsageEncrypt|kmip.CryptographicUsageDecrypt)
aes256 := client.Create().AES(256, kmip.CryptographicUsageEncrypt|kmip.CryptographicUsageDecrypt)
// Other symmetric algorithms
tdes := client.Create().TDES(192, kmip.CryptographicUsageEncrypt)
skipjack := client.Create().Skipjack(kmip.CryptographicUsageEncrypt) // 80-bit key
// With attributes
key := client.Create().
AES(256, kmip.CryptographicUsageEncrypt|kmip.CryptographicUsageDecrypt).
WithName("my-encryption-key").
WithAttribute(kmip.AttributeNameDescription, "Production encryption key").
WithUsageLimit(1000000, kmip.UsageLimitsUnitByte).
MustExec()
```
#### 非对称密钥对
```
// RSA Key Pairs
rsaKeyPair := client.CreateKeyPair().
RSA(2048, kmip.CryptographicUsageSign, kmip.CryptographicUsageVerify).
WithName("my-rsa-keypair").
MustExec()
// ECDSA Key Pairs
ecdsaKeyPair := client.CreateKeyPair().
ECDSA(kmip.RecommendedCurveP_256, kmip.CryptographicUsageSign, kmip.CryptographicUsageVerify).
WithName("my-ecdsa-keypair").
MustExec()
// Access individual keys
fmt.Printf("Private Key ID: %s\n", ecdsaKeyPair.PrivateKeyUniqueIdentifier)
fmt.Printf("Public Key ID: %s\n", ecdsaKeyPair.PublicKeyUniqueIdentifier
```
#### 对象注册
```
// Register existing cryptographic material
registered := client.Register().
Object(existingKeyObject).
WithName("imported-object").
MustExec()
// Register with specific attributes
cert := client.Register().
Certificate(kmip.CertificateTypeX_509, x509Cert).
WithName("server-certificate").
WithAttribute(kmip.AttributeNameCertificateType, kmip.CertificateTypeX_509).
MustExec()
```
### 加密操作
#### 加密和解密
```
// Basic encryption
plaintext := []byte("sensitive data")
encrypted := client.Encrypt(keyID).
WithCryptographicParameters(kmip.CryptographicParameters{ /* parameters */ }).
Data(plaintext).
MustExec()
// Encryption with specific parameters
encrypted := client.Encrypt(keyID).
WithCryptographicParameters(kmip.AES_GCM).
WithIvCounterNonce(iv).
WithAAD(additionalData).
Data(plaintext).
MustExec()
// Decryption
decrypted := client.Decrypt(keyID).
WithCryptographicParameters(kmip.AES_GCM).
WithIvCounterNonce(encrypted.IVCounterNonce).
WithAAD(additionalData).
WithAuthTag(encrypted.AuthenticatedEncryptionTag).
Data(encrypted.Data).
MustExec()
fmt.Printf("Decrypted: %s\n", decrypted.Data)
```
#### 数字签名
```
// Sign data
data := []byte("document to sign")
signature := client.Sign(privateKeyID).
WithCryptographicParameters(kmip.CryptographicParameters{ /* parameters */ }).
Data(data).
MustExec()
// Sign pre-hashed data
hashedData := sha256.Sum256(data)
signature = client.Sign(privateKeyID).
WithCryptographicParameters(kmip.CryptographicParameters{ /* parameters */ }).
DigestedData(hashedData[:]).
MustExec()
// Verify signature
verified := client.SignatureVerify(publicKeyID).
WithCryptographicParameters(kmip.CryptographicParameters{ /* parameters */ }).
Data(data).
Signature(signature.SignatureData).
MustExec()
fmt.Printf("Signature valid: %t\n", verified.ValidityIndicator == kmip.ValidityIndicatorValid)
```
#### Go crypto.Signer 接口
```
// Get a crypto.Signer for use with standard Go crypto packages
signer, err := client.Signer(ctx, privateKeyID, publicKeyID)
if err != nil {
log.Fatal(err)
}
// Use with crypto packages
hash := sha256.Sum256(data)
signature, err := signer.Sign(rand.Reader, hash[:], crypto.SHA256)
if err != nil {
log.Fatal(err)
}
// Use with x509 certificate signing
template := &x509.Certificate{/*...*/}
certDER, err := x509.CreateCertificate(rand.Reader, template, caCert, signer.Public(), signer)
```
### 密钥生命周期管理
#### 密钥状态和激活
```
// Activate a key
client.Activate(keyID).MustExec()
// Check key state
attrs := client.GetAttributes(keyID, kmip.AttributeNameState).MustExec()
for _, attr := range attrs.Attribute {
if attr.AttributeName == kmip.AttributeNameState {
fmt.Printf("Key state: %v\n", attr.AttributeValue)
}
}
// Revoke a key
client.Revoke(keyID).
WithRevocationReasonCode(kmip.RevocationReasonCodeKeyCompromise).
WithRevocationMessage("Security incident detected").
MustExec()
// Archive and recover
client.Archive(keyID).MustExec()
client.Recover(keyID).MustExec()
// Destroy key (irreversible)
client.Destroy(keyID).MustExec()
```
#### 属性管理
```
// Get all attributes
allAttrs := client.GetAttributes(keyID).MustExec()
// Get specific attributes
specificAttrs := client.GetAttributes(keyID,
kmip.AttributeNameState,
kmip.AttributeNameCryptographicUsageMask,
kmip.AttributeNameCryptographicLength,
).MustExec()
// Get attribute list (names only)
attrList := client.GetAttributeList(keyID).MustExec()
// Add attributes
client.AddAttribute(keyID, kmip.AttributeNameDescription, "Updated description").MustExec()
// Modify attributes
client.ModifyAttribute(keyID, kmip.AttributeNameName, kmip.Name{
NameType: kmip.NameTypeUninterpretedTextString,
NameValue: "updated-key-name",
}).MustExec()
// Delete attributes
client.DeleteAttribute(keyID, kmip.AttributeNameDescription).MustExec()
```
#### 密钥发现
```
// Find keys by name
keys := client.Locate().
WithName("production-key").
MustExec()
// Complex search criteria
keys = client.Locate().
WithObjectType(kmip.ObjectTypeSymmetricKey).
WithAttribute(kmip.AttributeNameCryptographicAlgorithm, kmip.CryptographicAlgorithmAES).
WithAttribute(kmip.AttributeNameCryptographicLength, int32(256)).
WithUsageLimit(1000000, kmip.UsageLimitsUnitByte).
MustExec()
for _, keyID := range keys.UniqueIdentifier {
fmt.Printf("Found key: %s\n", keyID)
}
```
### 批处理操作
```
// Hight-Level batch builder
result := client.Create().
AES(256, kmip.CryptographicUsageEncrypt|kmip.CryptographicUsageDecrypt).
WithName("batch-key").
Then(func(client *kmipclient.Client) kmipclient.PayloadBuilder {
// Use ID returned from previous operation
return client.Activate("")
}).
Then(func(client *kmipclient.Client) kmipclient.PayloadBuilder {
// Use ID returned from previous operation
return client.GetAttributes("", kmip.AttributeNameState)
}).
MustExec()
// Manual batch creation
createReq1 := &payloads.CreateRequestPayload{ /* ... */ }
createReq2 := &payloads.ActivateRequestPayload{ /* ... */ }
activateReq := &payloads.GetAttributesRequestPayload{ /* ... */ }
result, err = client.Batch(ctx, createReq1, createReq2, activateReq)
if err != nil {
log.Fatal(err)
}
// Process batch results
for i, resp := range result {
if err := resp.Err(); err != nil {
fmt.Printf("Operation %d failed: %s - %s\n", i+1, resp.ResultStatus, resp.ResultReason)
continue
}
switch payload := resp.ResponsePayload.(type) {
case *payloads.CreateResponsePayload:
fmt.Printf("Created key %d: %s\n", i+1, payload.UniqueIdentifier)
case *payloads.ActivateResponsePayload:
fmt.Printf("Activated key: %s\n", payload.UniqueIdentifier)
}
}
```
### 低级操作
```
// Direct payload construction for maximum control
request := payloads.CreateRequestPayload{
ObjectType: kmip.ObjectTypeSymmetricKey,
TemplateAttribute: kmip.TemplateAttribute{
Attribute: []kmip.Attribute{
{
AttributeName: kmip.AttributeNameCryptographicAlgorithm,
AttributeValue: kmip.CryptographicAlgorithmAES,
},
{
AttributeName: kmip.AttributeNameCryptographicLength,
AttributeValue: int32(256),
},
{
AttributeName: kmip.AttributeNameCryptographicUsageMask,
AttributeValue: kmip.CryptographicUsageEncrypt | kmip.CryptographicUsageDecrypt,
},
},
},
}
// Send request
response, err := client.Request(ctx, &request)
if err != nil {
log.Fatal(err)
}
keyID := response.(*payloads.CreateResponsePayload).UniqueIdentifier
```
## 🖥️ 服务器 API
```
package main
import (
"context"
"crypto/tls"
"log"
"net"
"github.com/ovh/kmip-go"
"github.com/ovh/kmip-go/kmipserver"
)
// Implement the RequestHandler interface
type MyKMIPHandler struct {
// Your key management backend
}
func (h *MyKMIPHandler) HandleRequest(ctx context.Context, req *kmip.RequestMessage) *kmip.ResponseMessage {
// Process KMIP request and return response
// Implement your key management logic here
return &kmip.ResponseMessage{
Header: kmip.ResponseHeader{
ProtocolVersion: req.Header.ProtocolVersion,
BatchCount: req.Header.BatchCount,
},
BatchItem: []kmip.ResponseBatchItem{
// Process each batch item
},
}
}
func main() {
// Setup TLS
cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
log.Fatal(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
}
// Create listener
listener, err := tls.Listen("tcp", ":5696", tlsConfig)
if err != nil {
log.Fatal(err)
}
// Create and start server
handler := &MyKMIPHandler{}
server := kmipserver.NewServer(listener, handler).
WithMaxMessageSize(2 * 1024 * 1024) // 2 MB limit (default: 1 MB, < 0 disables limit)
log.Println("Starting KMIP server on :5696")
if err := server.Serve(); err != nil {
log.Fatal(err)
}
}
```
## 🚀 高级功能
### 自定义中间件
```
// Rate limiting middleware
func RateLimitMiddleware(limiter *rate.Limiter) kmipclient.Middleware {
return func(next kmipclient.Next, ctx context.Context, req *kmip.RequestMessage) (*kmip.ResponseMessage, error) {
// Wait for rate limit
if err := limiter.Wait(ctx); err != nil {
return nil, fmt.Errorf("rate limit exceeded: %w", err)
}
return next(ctx, req)
}
}
// Retry middleware
func RetryMiddleware(maxRetries int) kmipclient.Middleware {
return func(next kmipclient.Next, ctx context.Context, req *kmip.RequestMessage) (*kmip.ResponseMessage, error) {
var lastErr error
for i := 0; i <= maxRetries; i++ {
resp, err := next(ctx, req)
if err == nil {
return resp, nil
}
lastErr = err
// Exponential backoff
if i < maxRetries {
backoff := time.Duration(1<
标签:Apache许可证, API, EVTX分析, Go语言, HTTPS, KMIP协议, TLS, 中间件, 加密操作, 协议实现, 安全通信, 客户端库, 密钥生命周期管理, 开源, 扩展性, 批量操作, 日志审计, 服务器库, 程序破解, 认证, 防御工具