github.com/zntrio/harp/v2@v2.0.9/pkg/container/identity/api.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package identity 19 20 import ( 21 "bytes" 22 "context" 23 "encoding/base64" 24 "encoding/json" 25 "errors" 26 "fmt" 27 "time" 28 29 "github.com/zntrio/harp/v2/pkg/container/identity/key" 30 "github.com/zntrio/harp/v2/pkg/sdk/types" 31 "github.com/zntrio/harp/v2/pkg/sdk/value" 32 ) 33 34 // Identity object to hold container sealer identity information. 35 type Identity struct { 36 APIVersion string `json:"@apiVersion"` 37 Kind string `json:"@kind"` 38 Timestamp time.Time `json:"@timestamp"` 39 Description string `json:"@description"` 40 Public string `json:"public"` 41 Private *PrivateKey `json:"private"` 42 Signature string `json:"signature"` 43 } 44 45 // HasPrivateKey returns true if identity as a wrapped private. 46 func (i *Identity) HasPrivateKey() bool { 47 return i.Private != nil 48 } 49 50 // Decrypt private key with given transformer. 51 func (i *Identity) Decrypt(ctx context.Context, t value.Transformer) (*key.JSONWebKey, error) { 52 // Check arguments 53 if types.IsNil(t) { 54 return nil, fmt.Errorf("can't process with nil transformer") 55 } 56 if !i.HasPrivateKey() { 57 return nil, fmt.Errorf("trying to decrypt a nil private key") 58 } 59 60 // Decode payload 61 payload, err := base64.RawURLEncoding.DecodeString(i.Private.Content) 62 if err != nil { 63 return nil, fmt.Errorf("unable to decode private key: %w", err) 64 } 65 66 // Apply transformation 67 clearText, err := t.From(ctx, payload) 68 if err != nil { 69 return nil, fmt.Errorf("unable to decrypt identity payload: %w", err) 70 } 71 72 // Decode key 73 var pk key.JSONWebKey 74 if err = json.NewDecoder(bytes.NewReader(clearText)).Decode(&pk); err != nil { 75 return nil, fmt.Errorf("unable to decode payload as JSON: %w", err) 76 } 77 78 // Return result 79 return &pk, nil 80 } 81 82 // Verify the identity signature using its own public key. 83 func (i *Identity) Verify() error { 84 // Clear the signature 85 id := &Identity{} 86 *id = *i 87 88 // Clean protected 89 id.Signature = "" 90 id.Private = nil 91 92 // Prepare protected 93 protected, err := json.Marshal(id) 94 if err != nil { 95 return fmt.Errorf("unable to serialize identity for signature: %w", err) 96 } 97 98 // Decode the signature 99 sig, err := base64.RawURLEncoding.DecodeString(i.Signature) 100 if err != nil { 101 return fmt.Errorf("unable to decode the signature: %w", err) 102 } 103 104 // Decode public key 105 pubKey, err := key.FromString(id.Public) 106 if err != nil { 107 return fmt.Errorf("unable to decode public key: %w", err) 108 } 109 110 // Validate signature 111 if pubKey.Verify(protected, sig) { 112 return nil 113 } 114 115 return errors.New("unable to validate identity signature") 116 } 117 118 // PrivateKey wraps encoded private and related informations. 119 type PrivateKey struct { 120 Encoding string `json:"encoding,omitempty"` 121 Content string `json:"content"` 122 }