certificate_retriever.go raw
1 // Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved.
2 // This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
3
4 package auth
5
6 import (
7 "bytes"
8 "crypto/rsa"
9 "crypto/x509"
10 "encoding/pem"
11 "fmt"
12 "sync"
13
14 "github.com/nrdcg/oci-go-sdk/common/v1065"
15 )
16
17 // x509CertificateRetriever provides an X509 certificate with the RSA private key
18 type x509CertificateRetriever interface {
19 Refresh() error
20 CertificatePemRaw() []byte
21 Certificate() *x509.Certificate
22 PrivateKeyPemRaw() []byte
23 PrivateKey() *rsa.PrivateKey
24 }
25
26 // urlBasedX509CertificateRetriever retrieves PEM-encoded X509 certificates from the given URLs.
27 type urlBasedX509CertificateRetriever struct {
28 certURL string
29 privateKeyURL string
30 passphrase string
31 certificatePemRaw []byte
32 certificate *x509.Certificate
33 privateKeyPemRaw []byte
34 privateKey *rsa.PrivateKey
35 mux sync.Mutex
36 dispatcher common.HTTPRequestDispatcher
37 }
38
39 func newURLBasedX509CertificateRetriever(dispatcher common.HTTPRequestDispatcher, certURL, privateKeyURL, passphrase string) x509CertificateRetriever {
40 return &urlBasedX509CertificateRetriever{
41 certURL: certURL,
42 privateKeyURL: privateKeyURL,
43 passphrase: passphrase,
44 mux: sync.Mutex{},
45 dispatcher: dispatcher,
46 }
47 }
48
49 // Refresh() is failure atomic, i.e., CertificatePemRaw(), Certificate(), PrivateKeyPemRaw(), and PrivateKey() would
50 // return their previous values if Refresh() fails.
51 func (r *urlBasedX509CertificateRetriever) Refresh() error {
52 common.Debugln("Refreshing certificate")
53
54 r.mux.Lock()
55 defer r.mux.Unlock()
56
57 var err error
58
59 var certificatePemRaw []byte
60 var certificate *x509.Certificate
61 if certificatePemRaw, certificate, err = r.renewCertificate(r.certURL); err != nil {
62 return fmt.Errorf("failed to renew certificate: %s", err.Error())
63 }
64
65 var privateKeyPemRaw []byte
66 var privateKey *rsa.PrivateKey
67 if r.privateKeyURL != "" {
68 if privateKeyPemRaw, privateKey, err = r.renewPrivateKey(r.privateKeyURL, r.passphrase); err != nil {
69 return fmt.Errorf("failed to renew private key: %s", err.Error())
70 }
71 }
72
73 r.certificatePemRaw = certificatePemRaw
74 r.certificate = certificate
75 r.privateKeyPemRaw = privateKeyPemRaw
76 r.privateKey = privateKey
77 return nil
78 }
79
80 func (r *urlBasedX509CertificateRetriever) renewCertificate(url string) (certificatePemRaw []byte, certificate *x509.Certificate, err error) {
81 var body bytes.Buffer
82 if body, _, err = httpGet(r.dispatcher, url); err != nil {
83 return nil, nil, fmt.Errorf("failed to get certificate from %s: %s", url, err.Error())
84 }
85
86 certificatePemRaw = body.Bytes()
87 var block *pem.Block
88 block, _ = pem.Decode(certificatePemRaw)
89 if block == nil {
90 return nil, nil, fmt.Errorf("failed to parse the new certificate, not valid pem data")
91 }
92
93 if certificate, err = x509.ParseCertificate(block.Bytes); err != nil {
94 return nil, nil, fmt.Errorf("failed to parse the new certificate: %s", err.Error())
95 }
96
97 return certificatePemRaw, certificate, nil
98 }
99
100 func (r *urlBasedX509CertificateRetriever) renewPrivateKey(url, passphrase string) (privateKeyPemRaw []byte, privateKey *rsa.PrivateKey, err error) {
101 var body bytes.Buffer
102 if body, _, err = httpGet(r.dispatcher, url); err != nil {
103 return nil, nil, fmt.Errorf("failed to get private key from %s: %s", url, err.Error())
104 }
105
106 privateKeyPemRaw = body.Bytes()
107 if privateKey, err = common.PrivateKeyFromBytes(privateKeyPemRaw, &passphrase); err != nil {
108 return nil, nil, fmt.Errorf("failed to parse the new private key: %s", err.Error())
109 }
110
111 return privateKeyPemRaw, privateKey, nil
112 }
113
114 func (r *urlBasedX509CertificateRetriever) CertificatePemRaw() []byte {
115 r.mux.Lock()
116 defer r.mux.Unlock()
117
118 if r.certificatePemRaw == nil {
119 return nil
120 }
121
122 c := make([]byte, len(r.certificatePemRaw))
123 copy(c, r.certificatePemRaw)
124 return c
125 }
126
127 func (r *urlBasedX509CertificateRetriever) Certificate() *x509.Certificate {
128 r.mux.Lock()
129 defer r.mux.Unlock()
130
131 if r.certificate == nil {
132 return nil
133 }
134
135 c := *r.certificate
136 return &c
137 }
138
139 func (r *urlBasedX509CertificateRetriever) PrivateKeyPemRaw() []byte {
140 r.mux.Lock()
141 defer r.mux.Unlock()
142
143 if r.privateKeyPemRaw == nil {
144 return nil
145 }
146
147 c := make([]byte, len(r.privateKeyPemRaw))
148 copy(c, r.privateKeyPemRaw)
149 return c
150 }
151
152 func (r *urlBasedX509CertificateRetriever) PrivateKey() *rsa.PrivateKey {
153 r.mux.Lock()
154 defer r.mux.Unlock()
155
156 //Nil Private keys are supported as part of a certificate
157 if r.privateKey == nil {
158 return nil
159 }
160
161 c := *r.privateKey
162 return &c
163 }
164
165 // staticCertificateRetriever serves certificates from static data
166 type staticCertificateRetriever struct {
167 Passphrase []byte
168 CertificatePem []byte
169 PrivateKeyPem []byte
170 certificate *x509.Certificate
171 privateKey *rsa.PrivateKey
172 mux sync.Mutex
173 }
174
175 // Refresh proccess the inputs into appropiate keys and certificates
176 func (r *staticCertificateRetriever) Refresh() error {
177 r.mux.Lock()
178 defer r.mux.Unlock()
179
180 certifcate, err := r.readCertificate()
181 if err != nil {
182 r.certificate = nil
183 return err
184 }
185 r.certificate = certifcate
186
187 key, err := r.readPrivateKey()
188 if err != nil {
189 r.privateKey = nil
190 return err
191 }
192 r.privateKey = key
193
194 return nil
195 }
196
197 func (r *staticCertificateRetriever) Certificate() *x509.Certificate {
198 r.mux.Lock()
199 defer r.mux.Unlock()
200
201 return r.certificate
202 }
203
204 func (r *staticCertificateRetriever) PrivateKey() *rsa.PrivateKey {
205 r.mux.Lock()
206 defer r.mux.Unlock()
207
208 return r.privateKey
209 }
210
211 func (r *staticCertificateRetriever) CertificatePemRaw() []byte {
212 r.mux.Lock()
213 defer r.mux.Unlock()
214
215 if r.CertificatePem == nil {
216 return nil
217 }
218
219 c := make([]byte, len(r.CertificatePem))
220 copy(c, r.CertificatePem)
221 return c
222 }
223
224 func (r *staticCertificateRetriever) PrivateKeyPemRaw() []byte {
225 r.mux.Lock()
226 defer r.mux.Unlock()
227
228 if r.PrivateKeyPem == nil {
229 return nil
230 }
231
232 c := make([]byte, len(r.PrivateKeyPem))
233 copy(c, r.PrivateKeyPem)
234 return c
235 }
236
237 func (r *staticCertificateRetriever) readCertificate() (certificate *x509.Certificate, err error) {
238 block, _ := pem.Decode(r.CertificatePem)
239 if block == nil {
240 return nil, fmt.Errorf("failed to parse the new certificate, not valid pem data")
241 }
242
243 if certificate, err = x509.ParseCertificate(block.Bytes); err != nil {
244 return nil, fmt.Errorf("failed to parse the new certificate: %s", err.Error())
245 }
246 return certificate, nil
247 }
248
249 func (r *staticCertificateRetriever) readPrivateKey() (*rsa.PrivateKey, error) {
250 if r.PrivateKeyPem == nil {
251 return nil, nil
252 }
253
254 var pass *string
255 if r.Passphrase == nil {
256 pass = nil
257 } else {
258 ss := string(r.Passphrase)
259 pass = &ss
260 }
261 return common.PrivateKeyFromBytes(r.PrivateKeyPem, pass)
262 }
263