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