helpers.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. // Package helpers implements utility functionality common to many
  2. // CFSSL packages.
  3. package helpers
  4. import (
  5. "bytes"
  6. "crypto"
  7. "crypto/ecdsa"
  8. "crypto/elliptic"
  9. "crypto/rsa"
  10. "crypto/tls"
  11. "crypto/x509"
  12. "crypto/x509/pkix"
  13. "encoding/asn1"
  14. "encoding/pem"
  15. "errors"
  16. "fmt"
  17. "os"
  18. "strings"
  19. "time"
  20. "github.com/cloudflare/cfssl/crypto/pkcs7"
  21. cferr "github.com/cloudflare/cfssl/errors"
  22. "github.com/cloudflare/cfssl/helpers/derhelpers"
  23. "github.com/cloudflare/cfssl/log"
  24. ct "github.com/google/certificate-transparency-go"
  25. cttls "github.com/google/certificate-transparency-go/tls"
  26. ctx509 "github.com/google/certificate-transparency-go/x509"
  27. "golang.org/x/crypto/ocsp"
  28. "golang.org/x/crypto/pkcs12"
  29. )
  30. // OneYear is a time.Duration representing a year's worth of seconds.
  31. const OneYear = 8760 * time.Hour
  32. // OneDay is a time.Duration representing a day's worth of seconds.
  33. const OneDay = 24 * time.Hour
  34. // DelegationUsage is the OID for the DelegationUseage extensions
  35. var DelegationUsage = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44}
  36. // DelegationExtension
  37. var DelegationExtension = pkix.Extension{
  38. Id: DelegationUsage,
  39. Critical: false,
  40. Value: []byte{0x05, 0x00}, // ASN.1 NULL
  41. }
  42. // InclusiveDate returns the time.Time representation of a date - 1
  43. // nanosecond. This allows time.After to be used inclusively.
  44. func InclusiveDate(year int, month time.Month, day int) time.Time {
  45. return time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Add(-1 * time.Nanosecond)
  46. }
  47. // Jul2012 is the July 2012 CAB Forum deadline for when CAs must stop
  48. // issuing certificates valid for more than 5 years.
  49. var Jul2012 = InclusiveDate(2012, time.July, 01)
  50. // Apr2015 is the April 2015 CAB Forum deadline for when CAs must stop
  51. // issuing certificates valid for more than 39 months.
  52. var Apr2015 = InclusiveDate(2015, time.April, 01)
  53. // KeyLength returns the bit size of ECDSA or RSA PublicKey
  54. func KeyLength(key interface{}) int {
  55. if key == nil {
  56. return 0
  57. }
  58. if ecdsaKey, ok := key.(*ecdsa.PublicKey); ok {
  59. return ecdsaKey.Curve.Params().BitSize
  60. } else if rsaKey, ok := key.(*rsa.PublicKey); ok {
  61. return rsaKey.N.BitLen()
  62. }
  63. return 0
  64. }
  65. // ExpiryTime returns the time when the certificate chain is expired.
  66. func ExpiryTime(chain []*x509.Certificate) (notAfter time.Time) {
  67. if len(chain) == 0 {
  68. return
  69. }
  70. notAfter = chain[0].NotAfter
  71. for _, cert := range chain {
  72. if notAfter.After(cert.NotAfter) {
  73. notAfter = cert.NotAfter
  74. }
  75. }
  76. return
  77. }
  78. // MonthsValid returns the number of months for which a certificate is valid.
  79. func MonthsValid(c *x509.Certificate) int {
  80. issued := c.NotBefore
  81. expiry := c.NotAfter
  82. years := (expiry.Year() - issued.Year())
  83. months := years*12 + int(expiry.Month()) - int(issued.Month())
  84. // Round up if valid for less than a full month
  85. if expiry.Day() > issued.Day() {
  86. months++
  87. }
  88. return months
  89. }
  90. // ValidExpiry determines if a certificate is valid for an acceptable
  91. // length of time per the CA/Browser Forum baseline requirements.
  92. // See https://cabforum.org/wp-content/uploads/CAB-Forum-BR-1.3.0.pdf
  93. func ValidExpiry(c *x509.Certificate) bool {
  94. issued := c.NotBefore
  95. var maxMonths int
  96. switch {
  97. case issued.After(Apr2015):
  98. maxMonths = 39
  99. case issued.After(Jul2012):
  100. maxMonths = 60
  101. case issued.Before(Jul2012):
  102. maxMonths = 120
  103. }
  104. if MonthsValid(c) > maxMonths {
  105. return false
  106. }
  107. return true
  108. }
  109. // SignatureString returns the TLS signature string corresponding to
  110. // an X509 signature algorithm.
  111. func SignatureString(alg x509.SignatureAlgorithm) string {
  112. switch alg {
  113. case x509.MD2WithRSA:
  114. return "MD2WithRSA"
  115. case x509.MD5WithRSA:
  116. return "MD5WithRSA"
  117. case x509.SHA1WithRSA:
  118. return "SHA1WithRSA"
  119. case x509.SHA256WithRSA:
  120. return "SHA256WithRSA"
  121. case x509.SHA384WithRSA:
  122. return "SHA384WithRSA"
  123. case x509.SHA512WithRSA:
  124. return "SHA512WithRSA"
  125. case x509.DSAWithSHA1:
  126. return "DSAWithSHA1"
  127. case x509.DSAWithSHA256:
  128. return "DSAWithSHA256"
  129. case x509.ECDSAWithSHA1:
  130. return "ECDSAWithSHA1"
  131. case x509.ECDSAWithSHA256:
  132. return "ECDSAWithSHA256"
  133. case x509.ECDSAWithSHA384:
  134. return "ECDSAWithSHA384"
  135. case x509.ECDSAWithSHA512:
  136. return "ECDSAWithSHA512"
  137. default:
  138. return "Unknown Signature"
  139. }
  140. }
  141. // HashAlgoString returns the hash algorithm name contains in the signature
  142. // method.
  143. func HashAlgoString(alg x509.SignatureAlgorithm) string {
  144. switch alg {
  145. case x509.MD2WithRSA:
  146. return "MD2"
  147. case x509.MD5WithRSA:
  148. return "MD5"
  149. case x509.SHA1WithRSA:
  150. return "SHA1"
  151. case x509.SHA256WithRSA:
  152. return "SHA256"
  153. case x509.SHA384WithRSA:
  154. return "SHA384"
  155. case x509.SHA512WithRSA:
  156. return "SHA512"
  157. case x509.DSAWithSHA1:
  158. return "SHA1"
  159. case x509.DSAWithSHA256:
  160. return "SHA256"
  161. case x509.ECDSAWithSHA1:
  162. return "SHA1"
  163. case x509.ECDSAWithSHA256:
  164. return "SHA256"
  165. case x509.ECDSAWithSHA384:
  166. return "SHA384"
  167. case x509.ECDSAWithSHA512:
  168. return "SHA512"
  169. default:
  170. return "Unknown Hash Algorithm"
  171. }
  172. }
  173. // StringTLSVersion returns underlying enum values from human names for TLS
  174. // versions, defaults to current golang default of TLS 1.0
  175. func StringTLSVersion(version string) uint16 {
  176. switch version {
  177. case "1.2":
  178. return tls.VersionTLS12
  179. case "1.1":
  180. return tls.VersionTLS11
  181. default:
  182. return tls.VersionTLS10
  183. }
  184. }
  185. // EncodeCertificatesPEM encodes a number of x509 certificates to PEM
  186. func EncodeCertificatesPEM(certs []*x509.Certificate) []byte {
  187. var buffer bytes.Buffer
  188. for _, cert := range certs {
  189. pem.Encode(&buffer, &pem.Block{
  190. Type: "CERTIFICATE",
  191. Bytes: cert.Raw,
  192. })
  193. }
  194. return buffer.Bytes()
  195. }
  196. // EncodeCertificatePEM encodes a single x509 certificates to PEM
  197. func EncodeCertificatePEM(cert *x509.Certificate) []byte {
  198. return EncodeCertificatesPEM([]*x509.Certificate{cert})
  199. }
  200. // ParseCertificatesPEM parses a sequence of PEM-encoded certificate and returns them,
  201. // can handle PEM encoded PKCS #7 structures.
  202. func ParseCertificatesPEM(certsPEM []byte) ([]*x509.Certificate, error) {
  203. var certs []*x509.Certificate
  204. var err error
  205. certsPEM = bytes.TrimSpace(certsPEM)
  206. for len(certsPEM) > 0 {
  207. var cert []*x509.Certificate
  208. cert, certsPEM, err = ParseOneCertificateFromPEM(certsPEM)
  209. if err != nil {
  210. return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
  211. } else if cert == nil {
  212. break
  213. }
  214. certs = append(certs, cert...)
  215. }
  216. if len(certsPEM) > 0 {
  217. return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
  218. }
  219. return certs, nil
  220. }
  221. // ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key,
  222. // either PKCS #7, PKCS #12, or raw x509.
  223. func ParseCertificatesDER(certsDER []byte, password string) (certs []*x509.Certificate, key crypto.Signer, err error) {
  224. certsDER = bytes.TrimSpace(certsDER)
  225. pkcs7data, err := pkcs7.ParsePKCS7(certsDER)
  226. if err != nil {
  227. var pkcs12data interface{}
  228. certs = make([]*x509.Certificate, 1)
  229. pkcs12data, certs[0], err = pkcs12.Decode(certsDER, password)
  230. if err != nil {
  231. certs, err = x509.ParseCertificates(certsDER)
  232. if err != nil {
  233. return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
  234. }
  235. } else {
  236. key = pkcs12data.(crypto.Signer)
  237. }
  238. } else {
  239. if pkcs7data.ContentInfo != "SignedData" {
  240. return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info"))
  241. }
  242. certs = pkcs7data.Content.SignedData.Certificates
  243. }
  244. if certs == nil {
  245. return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
  246. }
  247. return certs, key, nil
  248. }
  249. // ParseSelfSignedCertificatePEM parses a PEM-encoded certificate and check if it is self-signed.
  250. func ParseSelfSignedCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
  251. cert, err := ParseCertificatePEM(certPEM)
  252. if err != nil {
  253. return nil, err
  254. }
  255. if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil {
  256. return nil, cferr.Wrap(cferr.CertificateError, cferr.VerifyFailed, err)
  257. }
  258. return cert, nil
  259. }
  260. // ParseCertificatePEM parses and returns a PEM-encoded certificate,
  261. // can handle PEM encoded PKCS #7 structures.
  262. func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
  263. certPEM = bytes.TrimSpace(certPEM)
  264. cert, rest, err := ParseOneCertificateFromPEM(certPEM)
  265. if err != nil {
  266. // Log the actual parsing error but throw a default parse error message.
  267. log.Debugf("Certificate parsing error: %v", err)
  268. return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
  269. } else if cert == nil {
  270. return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
  271. } else if len(rest) > 0 {
  272. return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PEM file should contain only one object"))
  273. } else if len(cert) > 1 {
  274. return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate"))
  275. }
  276. return cert[0], nil
  277. }
  278. // ParseOneCertificateFromPEM attempts to parse one PEM encoded certificate object,
  279. // either a raw x509 certificate or a PKCS #7 structure possibly containing
  280. // multiple certificates, from the top of certsPEM, which itself may
  281. // contain multiple PEM encoded certificate objects.
  282. func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, error) {
  283. block, rest := pem.Decode(certsPEM)
  284. if block == nil {
  285. return nil, rest, nil
  286. }
  287. cert, err := x509.ParseCertificate(block.Bytes)
  288. if err != nil {
  289. pkcs7data, err := pkcs7.ParsePKCS7(block.Bytes)
  290. if err != nil {
  291. return nil, rest, err
  292. }
  293. if pkcs7data.ContentInfo != "SignedData" {
  294. return nil, rest, errors.New("only PKCS #7 Signed Data Content Info supported for certificate parsing")
  295. }
  296. certs := pkcs7data.Content.SignedData.Certificates
  297. if certs == nil {
  298. return nil, rest, errors.New("PKCS #7 structure contains no certificates")
  299. }
  300. return certs, rest, nil
  301. }
  302. var certs = []*x509.Certificate{cert}
  303. return certs, rest, nil
  304. }
  305. // LoadPEMCertPool loads a pool of PEM certificates from file.
  306. func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
  307. if certsFile == "" {
  308. return nil, nil
  309. }
  310. pemCerts, err := os.ReadFile(certsFile)
  311. if err != nil {
  312. return nil, err
  313. }
  314. return PEMToCertPool(pemCerts)
  315. }
  316. // PEMToCertPool concerts PEM certificates to a CertPool.
  317. func PEMToCertPool(pemCerts []byte) (*x509.CertPool, error) {
  318. if len(pemCerts) == 0 {
  319. return nil, nil
  320. }
  321. certPool := x509.NewCertPool()
  322. if !certPool.AppendCertsFromPEM(pemCerts) {
  323. return nil, errors.New("failed to load cert pool")
  324. }
  325. return certPool, nil
  326. }
  327. // ParsePrivateKeyPEM parses and returns a PEM-encoded private
  328. // key. The private key may be either an unencrypted PKCS#8, PKCS#1,
  329. // or elliptic private key.
  330. func ParsePrivateKeyPEM(keyPEM []byte) (key crypto.Signer, err error) {
  331. return ParsePrivateKeyPEMWithPassword(keyPEM, nil)
  332. }
  333. // ParsePrivateKeyPEMWithPassword parses and returns a PEM-encoded private
  334. // key. The private key may be a potentially encrypted PKCS#8, PKCS#1,
  335. // or elliptic private key.
  336. func ParsePrivateKeyPEMWithPassword(keyPEM []byte, password []byte) (key crypto.Signer, err error) {
  337. keyDER, err := GetKeyDERFromPEM(keyPEM, password)
  338. if err != nil {
  339. return nil, err
  340. }
  341. return derhelpers.ParsePrivateKeyDER(keyDER)
  342. }
  343. // GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes.
  344. func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) {
  345. // Ignore any EC PARAMETERS blocks when looking for a key (openssl includes
  346. // them by default).
  347. var keyDER *pem.Block
  348. for {
  349. keyDER, in = pem.Decode(in)
  350. if keyDER == nil || keyDER.Type != "EC PARAMETERS" {
  351. break
  352. }
  353. }
  354. if keyDER != nil {
  355. if procType, ok := keyDER.Headers["Proc-Type"]; ok {
  356. if strings.Contains(procType, "ENCRYPTED") {
  357. if password != nil {
  358. return x509.DecryptPEMBlock(keyDER, password)
  359. }
  360. return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted)
  361. }
  362. }
  363. return keyDER.Bytes, nil
  364. }
  365. return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
  366. }
  367. // ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request.
  368. func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) {
  369. in = bytes.TrimSpace(in)
  370. p, rest := pem.Decode(in)
  371. if p != nil {
  372. if p.Type != "NEW CERTIFICATE REQUEST" && p.Type != "CERTIFICATE REQUEST" {
  373. return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest)
  374. }
  375. csr, err = x509.ParseCertificateRequest(p.Bytes)
  376. } else {
  377. csr, err = x509.ParseCertificateRequest(in)
  378. }
  379. if err != nil {
  380. return nil, rest, err
  381. }
  382. err = csr.CheckSignature()
  383. if err != nil {
  384. return nil, rest, err
  385. }
  386. return csr, rest, nil
  387. }
  388. // ParseCSRPEM parses a PEM-encoded certificate signing request.
  389. // It does not check the signature. This is useful for dumping data from a CSR
  390. // locally.
  391. func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
  392. block, _ := pem.Decode([]byte(csrPEM))
  393. if block == nil {
  394. return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
  395. }
  396. csrObject, err := x509.ParseCertificateRequest(block.Bytes)
  397. if err != nil {
  398. return nil, err
  399. }
  400. return csrObject, nil
  401. }
  402. // SignerAlgo returns an X.509 signature algorithm from a crypto.Signer.
  403. func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
  404. switch pub := priv.Public().(type) {
  405. case *rsa.PublicKey:
  406. bitLength := pub.N.BitLen()
  407. switch {
  408. case bitLength >= 4096:
  409. return x509.SHA512WithRSA
  410. case bitLength >= 3072:
  411. return x509.SHA384WithRSA
  412. case bitLength >= 2048:
  413. return x509.SHA256WithRSA
  414. default:
  415. return x509.SHA1WithRSA
  416. }
  417. case *ecdsa.PublicKey:
  418. switch pub.Curve {
  419. case elliptic.P521():
  420. return x509.ECDSAWithSHA512
  421. case elliptic.P384():
  422. return x509.ECDSAWithSHA384
  423. case elliptic.P256():
  424. return x509.ECDSAWithSHA256
  425. default:
  426. return x509.ECDSAWithSHA1
  427. }
  428. default:
  429. return x509.UnknownSignatureAlgorithm
  430. }
  431. }
  432. // LoadClientCertificate load key/certificate from pem files
  433. func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, error) {
  434. if certFile != "" && keyFile != "" {
  435. cert, err := tls.LoadX509KeyPair(certFile, keyFile)
  436. if err != nil {
  437. log.Criticalf("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
  438. return nil, err
  439. }
  440. log.Debug("Client certificate loaded ")
  441. return &cert, nil
  442. }
  443. return nil, nil
  444. }
  445. // CreateTLSConfig creates a tls.Config object from certs and roots
  446. func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Config {
  447. var certs []tls.Certificate
  448. if cert != nil {
  449. certs = []tls.Certificate{*cert}
  450. }
  451. return &tls.Config{
  452. Certificates: certs,
  453. RootCAs: remoteCAs,
  454. }
  455. }
  456. // SerializeSCTList serializes a list of SCTs.
  457. func SerializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) {
  458. list := ctx509.SignedCertificateTimestampList{}
  459. for _, sct := range sctList {
  460. sctBytes, err := cttls.Marshal(sct)
  461. if err != nil {
  462. return nil, err
  463. }
  464. list.SCTList = append(list.SCTList, ctx509.SerializedSCT{Val: sctBytes})
  465. }
  466. return cttls.Marshal(list)
  467. }
  468. // DeserializeSCTList deserializes a list of SCTs.
  469. func DeserializeSCTList(serializedSCTList []byte) ([]ct.SignedCertificateTimestamp, error) {
  470. var sctList ctx509.SignedCertificateTimestampList
  471. rest, err := cttls.Unmarshal(serializedSCTList, &sctList)
  472. if err != nil {
  473. return nil, err
  474. }
  475. if len(rest) != 0 {
  476. return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT list contained trailing garbage"))
  477. }
  478. list := make([]ct.SignedCertificateTimestamp, len(sctList.SCTList))
  479. for i, serializedSCT := range sctList.SCTList {
  480. var sct ct.SignedCertificateTimestamp
  481. rest, err := cttls.Unmarshal(serializedSCT.Val, &sct)
  482. if err != nil {
  483. return nil, err
  484. }
  485. if len(rest) != 0 {
  486. return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT contained trailing garbage"))
  487. }
  488. list[i] = sct
  489. }
  490. return list, nil
  491. }
  492. // SCTListFromOCSPResponse extracts the SCTList from an ocsp.Response,
  493. // returning an empty list if the SCT extension was not found or could not be
  494. // unmarshalled.
  495. func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTimestamp, error) {
  496. // This loop finds the SCTListExtension in the OCSP response.
  497. var SCTListExtension, ext pkix.Extension
  498. for _, ext = range response.Extensions {
  499. // sctExtOid is the ObjectIdentifier of a Signed Certificate Timestamp.
  500. sctExtOid := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5}
  501. if ext.Id.Equal(sctExtOid) {
  502. SCTListExtension = ext
  503. break
  504. }
  505. }
  506. // This code block extracts the sctList from the SCT extension.
  507. var sctList []ct.SignedCertificateTimestamp
  508. var err error
  509. if numBytes := len(SCTListExtension.Value); numBytes != 0 {
  510. var serializedSCTList []byte
  511. rest := make([]byte, numBytes)
  512. copy(rest, SCTListExtension.Value)
  513. for len(rest) != 0 {
  514. rest, err = asn1.Unmarshal(rest, &serializedSCTList)
  515. if err != nil {
  516. return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
  517. }
  518. }
  519. sctList, err = DeserializeSCTList(serializedSCTList)
  520. }
  521. return sctList, err
  522. }
  523. // ReadBytes reads a []byte either from a file or an environment variable.
  524. // If valFile has a prefix of 'env:', the []byte is read from the environment
  525. // using the subsequent name. If the prefix is 'file:' the []byte is read from
  526. // the subsequent file. If no prefix is provided, valFile is assumed to be a
  527. // file path.
  528. func ReadBytes(valFile string) ([]byte, error) {
  529. switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) {
  530. case 1:
  531. return os.ReadFile(valFile)
  532. case 2:
  533. switch splitVal[0] {
  534. case "env":
  535. return []byte(os.Getenv(splitVal[1])), nil
  536. case "file":
  537. return os.ReadFile(splitVal[1])
  538. default:
  539. return nil, fmt.Errorf("unknown prefix: %s", splitVal[0])
  540. }
  541. default:
  542. return nil, fmt.Errorf("multiple prefixes: %s",
  543. strings.Join(splitVal[:len(splitVal)-1], ", "))
  544. }
  545. }