github.com/zntrio/harp/v2@v2.0.9/pkg/tasks/keygen/jwk.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 keygen 19 20 import ( 21 "context" 22 "crypto" 23 "crypto/ecdsa" 24 "crypto/ed25519" 25 "crypto/elliptic" 26 "crypto/rand" 27 "crypto/rsa" 28 "encoding/json" 29 "errors" 30 "fmt" 31 "io" 32 33 "gopkg.in/square/go-jose.v2" 34 35 "github.com/zntrio/harp/v2/pkg/tasks" 36 ) 37 38 // BundleDumpTask implements secret-container creation from a Bundle Dump. 39 type JWKTask struct { 40 SignatureAlgorithm string 41 KeySize int 42 KeyID string 43 OutputWriter tasks.WriterProvider 44 } 45 46 // Run the task. 47 func (t *JWKTask) Run(ctx context.Context) error { 48 var ( 49 writer io.Writer 50 err error 51 ) 52 53 // Generate key 54 _, sk, err := t.keygenSig(jose.SignatureAlgorithm(t.SignatureAlgorithm), t.KeySize) 55 if err != nil { 56 return fmt.Errorf("unable to generate key pair: %w", err) 57 } 58 59 // Wrap as JWK 60 priv := jose.JSONWebKey{ 61 Key: sk, 62 KeyID: t.KeyID, 63 Algorithm: t.SignatureAlgorithm, 64 } 65 66 // Create output writer 67 writer, err = t.OutputWriter(ctx) 68 if err != nil { 69 return fmt.Errorf("unable to open output writer: %w", err) 70 } 71 72 // Encode as JSON 73 if err := json.NewEncoder(writer).Encode(priv); err != nil { 74 return fmt.Errorf("unable to encode JWK: %w", err) 75 } 76 77 // No error 78 return nil 79 } 80 81 // ----------------------------------------------------------------------------- 82 83 // KeygenSig generates keypair for corresponding SignatureAlgorithm. 84 // 85 //nolint:gocyclo // to refactor 86 func (t *JWKTask) keygenSig(alg jose.SignatureAlgorithm, bits int) (crypto.PublicKey, crypto.PrivateKey, error) { 87 switch alg { 88 case jose.ES256, jose.ES384, jose.ES512, jose.EdDSA: 89 keylen := map[jose.SignatureAlgorithm]int{ 90 jose.ES256: 256, 91 jose.ES384: 384, 92 jose.ES512: 521, // sic! 93 jose.EdDSA: 256, 94 } 95 if bits != 0 && bits != keylen[alg] { 96 return nil, nil, errors.New("this `alg` does not support arbitrary key length") 97 } 98 case jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512: 99 if bits == 0 { 100 bits = 2048 101 } 102 if bits < 2048 { 103 return nil, nil, errors.New("too short key for RSA `alg`, 2048+ is required") 104 } 105 case jose.HS256, jose.HS384, jose.HS512: 106 return nil, nil, fmt.Errorf("can't generate crypto keys for %q signature", alg) 107 } 108 switch alg { 109 case jose.ES256: 110 // The cryptographic operations are implemented using constant-time algorithms. 111 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 112 if err != nil { 113 return nil, nil, err 114 } 115 pub := key.Public() 116 return pub, key, err 117 case jose.ES384: 118 // NB: The cryptographic operations do not use constant-time algorithms. 119 key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) 120 if err != nil { 121 return nil, nil, err 122 } 123 pub := key.Public() 124 return pub, key, err 125 case jose.ES512: 126 // NB: The cryptographic operations do not use constant-time algorithms. 127 key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) 128 if err != nil { 129 return nil, nil, err 130 } 131 pub := key.Public() 132 return pub, key, err 133 case jose.EdDSA: 134 pub, key, err := ed25519.GenerateKey(rand.Reader) 135 return pub, key, err 136 case jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512: 137 key, err := rsa.GenerateKey(rand.Reader, bits) 138 if err != nil { 139 return nil, nil, err 140 } 141 pub := key.Public() 142 return pub, key, err 143 case jose.HS256, jose.HS384, jose.HS512: 144 return nil, nil, fmt.Errorf("can't generate crypto keys for %q signature", alg) 145 default: 146 return nil, nil, errors.New("unknown signature algorithm provided") 147 } 148 }