go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/certutil/key_pair.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package certutil 9 10 import ( 11 "crypto/tls" 12 "crypto/x509" 13 "encoding/base64" 14 "os" 15 16 "go.charczuk.com/sdk/errutil" 17 ) 18 19 // NewKeyPairFromPaths returns a key pair from paths. 20 func NewKeyPairFromPaths(certPath, keyPath string) KeyPair { 21 return KeyPair{CertPath: certPath, KeyPath: keyPath} 22 } 23 24 // KeyPair is an x509 pem key pair as strings. 25 type KeyPair struct { 26 Cert string `json:"cert,omitempty" yaml:"cert,omitempty"` 27 CertBase64 string `json:"certBase64,omitempty" yaml:"certBase64,omitempty"` 28 CertPath string `json:"certPath,omitempty" yaml:"certPath,omitempty"` 29 Key string `json:"key,omitempty" yaml:"key,omitempty"` 30 KeyBase64 string `json:"keyBase64,omitempty" yaml:"keyBase64,omitempty"` 31 KeyPath string `json:"keyPath,omitempty" yaml:"keyPath,omitempty"` 32 } 33 34 // IsZero returns if the key pair is set or not. 35 func (kp KeyPair) IsZero() bool { 36 return kp.Cert == "" && 37 kp.Key == "" && 38 kp.CertPath == "" && 39 kp.KeyPath == "" 40 } 41 42 // IsCertPath returns if the keypair cert is a path. 43 func (kp KeyPair) IsCertPath() bool { 44 return kp.Cert == "" && kp.CertPath != "" 45 } 46 47 // IsKeyPath returns if the keypair key is a path. 48 func (kp KeyPair) IsKeyPath() bool { 49 return kp.Key == "" && kp.KeyPath != "" 50 } 51 52 // CertBytes returns the key pair cert bytes. 53 func (kp KeyPair) CertBytes() ([]byte, error) { 54 if kp.Cert != "" { 55 return []byte(kp.Cert), nil 56 } 57 if kp.CertBase64 != "" { 58 return base64.StdEncoding.DecodeString(kp.CertBase64) 59 } 60 if kp.CertPath == "" { 61 return nil, errutil.New("error loading cert; no sources for cert data set") 62 } 63 contents, err := os.ReadFile(os.ExpandEnv(kp.CertPath)) 64 if err != nil { 65 return nil, errutil.New("error loading cert from path", errutil.OptInner(err), errutil.OptMessage(kp.CertPath)) 66 } 67 return contents, nil 68 } 69 70 // KeyBytes returns the key pair key bytes. 71 func (kp KeyPair) KeyBytes() ([]byte, error) { 72 if kp.Key != "" { 73 return []byte(kp.Key), nil 74 } 75 if kp.KeyBase64 != "" { 76 return base64.StdEncoding.DecodeString(kp.KeyBase64) 77 } 78 if kp.KeyPath == "" { 79 return nil, errutil.New("error loading key; no sources for key data set") 80 } 81 contents, err := os.ReadFile(os.ExpandEnv(kp.KeyPath)) 82 if err != nil { 83 return nil, errutil.New("error loading key from path", errutil.OptInner(err), errutil.OptMessage(kp.KeyPath)) 84 } 85 return contents, nil 86 } 87 88 // String returns a string representation of the key pair. 89 func (kp KeyPair) String() (output string) { 90 output = "[ " 91 if kp.Cert != "" { 92 output += "cert: <literal>" 93 } else if kp.CertPath != "" { 94 output += ("cert: " + os.ExpandEnv(kp.CertPath)) 95 } 96 if kp.Key != "" { 97 output += ", key: <literal>" 98 } else if kp.KeyPath != "" { 99 output += (", key: " + os.ExpandEnv(kp.KeyPath)) 100 } 101 output += " ]" 102 return output 103 } 104 105 // TLSCertificate returns the KeyPair as a tls.Certificate. 106 func (kp KeyPair) TLSCertificate() (cert tls.Certificate, err error) { 107 certBytes, err := kp.CertBytes() 108 if err != nil { 109 err = errutil.New(err) 110 return 111 } 112 keyBytes, err := kp.KeyBytes() 113 if err != nil { 114 err = errutil.New(err) 115 return 116 } 117 cert, err = tls.X509KeyPair(certBytes, keyBytes) 118 if err != nil { 119 err = errutil.New(err) 120 return 121 } 122 return 123 } 124 125 // TLSCertificateWithLeaf returns the KeyPair as a tls.Certificate. 126 func (kp KeyPair) TLSCertificateWithLeaf() (cert tls.Certificate, err error) { 127 cert, err = kp.TLSCertificate() 128 if err != nil { 129 err = errutil.New(err) 130 return 131 } 132 if len(cert.Certificate) == 0 { 133 err = errutil.New("invalid certificate; empty certificate list") 134 return 135 } 136 if cert.Leaf == nil { 137 cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) 138 if err != nil { 139 err = errutil.New(err) 140 return 141 } 142 } 143 return 144 } 145 146 func (kp KeyPair) TLSConfig() (*tls.Config, error) { 147 cert, err := kp.TLSCertificate() 148 if err != nil { 149 return nil, err 150 } 151 config := new(tls.Config) 152 config.Certificates = []tls.Certificate{cert} 153 return config, nil 154 }