ovh/kmip-go

GitHub: ovh/kmip-go

kmip-go是一个支持KMIP协议的Go语言库,用于实现密钥管理系统。

Stars: 37 | Forks: 10

# kmip-go [![Go 参考文档](https://pkg.go.dev/badge/github.com/ovh/kmip-go.svg)](https://pkg.go.dev/github.com/ovh/kmip-go) [![许可证](https://img.shields.io/badge/license-Apache%202.0-red.svg?style=flat)](https://raw.githubusercontent.com/ovh/kmip-go/master/LICENSE) [![测试](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/26b0134166065448.svg)](https://github.com/ovh/kmip-go/actions/workflows/test.yaml) [![Go Report Card](https://goreportcard.com/badge/github.com/ovh/kmip-go)](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, 中间件, 加密操作, 协议实现, 安全通信, 客户端库, 密钥生命周期管理, 开源, 扩展性, 批量操作, 日志审计, 服务器库, 程序破解, 认证, 防御工具