pkcs12.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package template
  13. import (
  14. "bytes"
  15. "crypto/x509"
  16. "encoding/base64"
  17. "encoding/pem"
  18. "fmt"
  19. "golang.org/x/crypto/pkcs12"
  20. gopkcs12 "software.sslmate.com/src/go-pkcs12"
  21. )
  22. func pkcs12keyPass(pass, input string) (string, error) {
  23. blocks, err := pkcs12.ToPEM([]byte(input), pass)
  24. if err != nil {
  25. return "", fmt.Errorf(errDecodePKCS12WithPass, err)
  26. }
  27. var pemData []byte
  28. for _, block := range blocks {
  29. // remove bag attributes like localKeyID, friendlyName
  30. block.Headers = nil
  31. if block.Type == pemTypeCertificate {
  32. continue
  33. }
  34. key, err := parsePrivateKey(block.Bytes)
  35. if err != nil {
  36. return "", err
  37. }
  38. // we use pkcs8 because it supports more key types (ecdsa, ed25519), not just RSA
  39. block.Bytes, err = x509.MarshalPKCS8PrivateKey(key)
  40. if err != nil {
  41. return "", err
  42. }
  43. // report error if encode fails
  44. var buf bytes.Buffer
  45. if err := pem.Encode(&buf, block); err != nil {
  46. return "", err
  47. }
  48. pemData = append(pemData, buf.Bytes()...)
  49. }
  50. return string(pemData), nil
  51. }
  52. func parsePrivateKey(block []byte) (interface{}, error) {
  53. if k, err := x509.ParsePKCS1PrivateKey(block); err == nil {
  54. return k, nil
  55. }
  56. if k, err := x509.ParsePKCS8PrivateKey(block); err == nil {
  57. return k, nil
  58. }
  59. if k, err := x509.ParseECPrivateKey(block); err == nil {
  60. return k, nil
  61. }
  62. return nil, fmt.Errorf(errParsePrivKey)
  63. }
  64. func pkcs12key(input string) (string, error) {
  65. return pkcs12keyPass("", input)
  66. }
  67. func pkcs12certPass(pass, input string) (string, error) {
  68. blocks, err := pkcs12.ToPEM([]byte(input), pass)
  69. if err != nil {
  70. return "", fmt.Errorf(errDecodeCertWithPass, err)
  71. }
  72. var pemData []byte
  73. for _, block := range blocks {
  74. if block.Type != pemTypeCertificate {
  75. continue
  76. }
  77. // remove bag attributes like localKeyID, friendlyName
  78. block.Headers = nil
  79. // report error if encode fails
  80. var buf bytes.Buffer
  81. if err := pem.Encode(&buf, block); err != nil {
  82. return "", err
  83. }
  84. pemData = append(pemData, buf.Bytes()...)
  85. }
  86. // try to order certificate chain. If it fails we return
  87. // the unordered raw pem data.
  88. // This fails if multiple leaf or disjunct certs are provided.
  89. ordered, err := fetchCertChains(pemData)
  90. if err != nil {
  91. return string(pemData), nil
  92. }
  93. return string(ordered), nil
  94. }
  95. func pkcs12cert(input string) (string, error) {
  96. return pkcs12certPass("", input)
  97. }
  98. func pemToPkcs12(cert, key string) (string, error) {
  99. return pemToPkcs12Pass(cert, key, "")
  100. }
  101. func pemToPkcs12Pass(cert, key, pass string) (string, error) {
  102. certPem, _ := pem.Decode([]byte(cert))
  103. keyPem, _ := pem.Decode([]byte(key))
  104. parsedCert, err := x509.ParseCertificate(certPem.Bytes)
  105. if err != nil {
  106. return "", err
  107. }
  108. parsedKey, err := parsePrivateKey(keyPem.Bytes)
  109. if err != nil {
  110. return "", err
  111. }
  112. pfx, err := gopkcs12.Modern.Encode(parsedKey, parsedCert, nil, pass)
  113. if err != nil {
  114. return "", err
  115. }
  116. return base64.StdEncoding.EncodeToString(pfx), nil
  117. }