key_files.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package libtrust
  2. import (
  3. "encoding/json"
  4. "encoding/pem"
  5. "errors"
  6. "fmt"
  7. "io/ioutil"
  8. "os"
  9. "strings"
  10. )
  11. var (
  12. // ErrKeyFileDoesNotExist indicates that the private key file does not exist.
  13. ErrKeyFileDoesNotExist = errors.New("key file does not exist")
  14. )
  15. func readKeyFileBytes(filename string) ([]byte, error) {
  16. data, err := ioutil.ReadFile(filename)
  17. if err != nil {
  18. if os.IsNotExist(err) {
  19. err = ErrKeyFileDoesNotExist
  20. } else {
  21. err = fmt.Errorf("unable to read key file %s: %s", filename, err)
  22. }
  23. return nil, err
  24. }
  25. return data, nil
  26. }
  27. /*
  28. Loading and Saving of Public and Private Keys in either PEM or JWK format.
  29. */
  30. // LoadKeyFile opens the given filename and attempts to read a Private Key
  31. // encoded in either PEM or JWK format (if .json or .jwk file extension).
  32. func LoadKeyFile(filename string) (PrivateKey, error) {
  33. contents, err := readKeyFileBytes(filename)
  34. if err != nil {
  35. return nil, err
  36. }
  37. var key PrivateKey
  38. if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
  39. key, err = UnmarshalPrivateKeyJWK(contents)
  40. if err != nil {
  41. return nil, fmt.Errorf("unable to decode private key JWK: %s", err)
  42. }
  43. } else {
  44. key, err = UnmarshalPrivateKeyPEM(contents)
  45. if err != nil {
  46. return nil, fmt.Errorf("unable to decode private key PEM: %s", err)
  47. }
  48. }
  49. return key, nil
  50. }
  51. // LoadPublicKeyFile opens the given filename and attempts to read a Public Key
  52. // encoded in either PEM or JWK format (if .json or .jwk file extension).
  53. func LoadPublicKeyFile(filename string) (PublicKey, error) {
  54. contents, err := readKeyFileBytes(filename)
  55. if err != nil {
  56. return nil, err
  57. }
  58. var key PublicKey
  59. if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
  60. key, err = UnmarshalPublicKeyJWK(contents)
  61. if err != nil {
  62. return nil, fmt.Errorf("unable to decode public key JWK: %s", err)
  63. }
  64. } else {
  65. key, err = UnmarshalPublicKeyPEM(contents)
  66. if err != nil {
  67. return nil, fmt.Errorf("unable to decode public key PEM: %s", err)
  68. }
  69. }
  70. return key, nil
  71. }
  72. // SaveKey saves the given key to a file using the provided filename.
  73. // This process will overwrite any existing file at the provided location.
  74. func SaveKey(filename string, key PrivateKey) error {
  75. var encodedKey []byte
  76. var err error
  77. if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
  78. // Encode in JSON Web Key format.
  79. encodedKey, err = json.MarshalIndent(key, "", " ")
  80. if err != nil {
  81. return fmt.Errorf("unable to encode private key JWK: %s", err)
  82. }
  83. } else {
  84. // Encode in PEM format.
  85. pemBlock, err := key.PEMBlock()
  86. if err != nil {
  87. return fmt.Errorf("unable to encode private key PEM: %s", err)
  88. }
  89. encodedKey = pem.EncodeToMemory(pemBlock)
  90. }
  91. err = ioutil.WriteFile(filename, encodedKey, os.FileMode(0600))
  92. if err != nil {
  93. return fmt.Errorf("unable to write private key file %s: %s", filename, err)
  94. }
  95. return nil
  96. }
  97. // SavePublicKey saves the given public key to the file.
  98. func SavePublicKey(filename string, key PublicKey) error {
  99. var encodedKey []byte
  100. var err error
  101. if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
  102. // Encode in JSON Web Key format.
  103. encodedKey, err = json.MarshalIndent(key, "", " ")
  104. if err != nil {
  105. return fmt.Errorf("unable to encode public key JWK: %s", err)
  106. }
  107. } else {
  108. // Encode in PEM format.
  109. pemBlock, err := key.PEMBlock()
  110. if err != nil {
  111. return fmt.Errorf("unable to encode public key PEM: %s", err)
  112. }
  113. encodedKey = pem.EncodeToMemory(pemBlock)
  114. }
  115. err = ioutil.WriteFile(filename, encodedKey, os.FileMode(0644))
  116. if err != nil {
  117. return fmt.Errorf("unable to write public key file %s: %s", filename, err)
  118. }
  119. return nil
  120. }
  121. // Public Key Set files
  122. type jwkSet struct {
  123. Keys []json.RawMessage `json:"keys"`
  124. }
  125. // LoadKeySetFile loads a key set
  126. func LoadKeySetFile(filename string) ([]PublicKey, error) {
  127. if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
  128. return loadJSONKeySetFile(filename)
  129. }
  130. // Must be a PEM format file
  131. return loadPEMKeySetFile(filename)
  132. }
  133. func loadJSONKeySetRaw(data []byte) ([]json.RawMessage, error) {
  134. if len(data) == 0 {
  135. // This is okay, just return an empty slice.
  136. return []json.RawMessage{}, nil
  137. }
  138. keySet := jwkSet{}
  139. err := json.Unmarshal(data, &keySet)
  140. if err != nil {
  141. return nil, fmt.Errorf("unable to decode JSON Web Key Set: %s", err)
  142. }
  143. return keySet.Keys, nil
  144. }
  145. func loadJSONKeySetFile(filename string) ([]PublicKey, error) {
  146. contents, err := readKeyFileBytes(filename)
  147. if err != nil && err != ErrKeyFileDoesNotExist {
  148. return nil, err
  149. }
  150. return UnmarshalPublicKeyJWKSet(contents)
  151. }
  152. func loadPEMKeySetFile(filename string) ([]PublicKey, error) {
  153. data, err := readKeyFileBytes(filename)
  154. if err != nil && err != ErrKeyFileDoesNotExist {
  155. return nil, err
  156. }
  157. return UnmarshalPublicKeyPEMBundle(data)
  158. }
  159. // AddKeySetFile adds a key to a key set
  160. func AddKeySetFile(filename string, key PublicKey) error {
  161. if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
  162. return addKeySetJSONFile(filename, key)
  163. }
  164. // Must be a PEM format file
  165. return addKeySetPEMFile(filename, key)
  166. }
  167. func addKeySetJSONFile(filename string, key PublicKey) error {
  168. encodedKey, err := json.Marshal(key)
  169. if err != nil {
  170. return fmt.Errorf("unable to encode trusted client key: %s", err)
  171. }
  172. contents, err := readKeyFileBytes(filename)
  173. if err != nil && err != ErrKeyFileDoesNotExist {
  174. return err
  175. }
  176. rawEntries, err := loadJSONKeySetRaw(contents)
  177. if err != nil {
  178. return err
  179. }
  180. rawEntries = append(rawEntries, json.RawMessage(encodedKey))
  181. entriesWrapper := jwkSet{Keys: rawEntries}
  182. encodedEntries, err := json.MarshalIndent(entriesWrapper, "", " ")
  183. if err != nil {
  184. return fmt.Errorf("unable to encode trusted client keys: %s", err)
  185. }
  186. err = ioutil.WriteFile(filename, encodedEntries, os.FileMode(0644))
  187. if err != nil {
  188. return fmt.Errorf("unable to write trusted client keys file %s: %s", filename, err)
  189. }
  190. return nil
  191. }
  192. func addKeySetPEMFile(filename string, key PublicKey) error {
  193. // Encode to PEM, open file for appending, write PEM.
  194. file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, os.FileMode(0644))
  195. if err != nil {
  196. return fmt.Errorf("unable to open trusted client keys file %s: %s", filename, err)
  197. }
  198. defer file.Close()
  199. pemBlock, err := key.PEMBlock()
  200. if err != nil {
  201. return fmt.Errorf("unable to encoded trusted key: %s", err)
  202. }
  203. _, err = file.Write(pem.EncodeToMemory(pemBlock))
  204. if err != nil {
  205. return fmt.Errorf("unable to write trusted keys file: %s", err)
  206. }
  207. return nil
  208. }