pem.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. package cert
  2. import (
  3. "bytes"
  4. "encoding/pem"
  5. "errors"
  6. "fmt"
  7. "golang.org/x/crypto/ed25519"
  8. )
  9. var ErrTruncatedPEMBlock = errors.New("truncated PEM block")
  10. // SplitPEM is a split function for bufio.Scanner that returns each PEM block.
  11. func SplitPEM(data []byte, atEOF bool) (advance int, token []byte, err error) {
  12. // Look for the start of a PEM block
  13. start := bytes.Index(data, []byte("-----BEGIN "))
  14. if start == -1 {
  15. if atEOF && len(bytes.TrimSpace(data)) > 0 {
  16. // Non-whitespace content with no PEM block
  17. return 0, nil, ErrTruncatedPEMBlock
  18. }
  19. if atEOF {
  20. return len(data), nil, nil
  21. }
  22. // Request more data
  23. return 0, nil, nil
  24. }
  25. // Look for the end marker
  26. endMarkerStart := bytes.Index(data[start:], []byte("-----END "))
  27. if endMarkerStart == -1 {
  28. if atEOF {
  29. // Incomplete PEM block at EOF
  30. return 0, nil, ErrTruncatedPEMBlock
  31. }
  32. // Need more data to find the end
  33. return 0, nil, nil
  34. }
  35. // Find the actual end of the END line (after the newline)
  36. endMarkerStart += start
  37. endLineEnd := bytes.IndexByte(data[endMarkerStart:], '\n')
  38. var end int
  39. if endLineEnd == -1 {
  40. if atEOF {
  41. // END marker without newline at EOF - take it anyway
  42. end = len(data)
  43. } else {
  44. // Need more data
  45. return 0, nil, nil
  46. }
  47. } else {
  48. end = endMarkerStart + endLineEnd + 1
  49. }
  50. // Extract the PEM block
  51. pemBlock := data[start:end]
  52. // Return the valid PEM block
  53. return end, pemBlock, nil
  54. }
  55. const ( //cert banners
  56. CertificateBanner = "NEBULA CERTIFICATE"
  57. CertificateV2Banner = "NEBULA CERTIFICATE V2"
  58. )
  59. const ( //key-agreement-key banners
  60. X25519PrivateKeyBanner = "NEBULA X25519 PRIVATE KEY"
  61. X25519PublicKeyBanner = "NEBULA X25519 PUBLIC KEY"
  62. P256PrivateKeyBanner = "NEBULA P256 PRIVATE KEY"
  63. P256PublicKeyBanner = "NEBULA P256 PUBLIC KEY"
  64. )
  65. /* including "ECDSA" in the P256 banners is a clue that these keys should be used only for signing */
  66. const ( //signing key banners
  67. EncryptedECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 ENCRYPTED PRIVATE KEY"
  68. ECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 PRIVATE KEY"
  69. ECDSAP256PublicKeyBanner = "NEBULA ECDSA P256 PUBLIC KEY"
  70. EncryptedEd25519PrivateKeyBanner = "NEBULA ED25519 ENCRYPTED PRIVATE KEY"
  71. Ed25519PrivateKeyBanner = "NEBULA ED25519 PRIVATE KEY"
  72. Ed25519PublicKeyBanner = "NEBULA ED25519 PUBLIC KEY"
  73. )
  74. // UnmarshalCertificateFromPEM will try to unmarshal the first pem block in a byte array, returning any non consumed
  75. // data or an error on failure
  76. func UnmarshalCertificateFromPEM(b []byte) (Certificate, []byte, error) {
  77. p, r := pem.Decode(b)
  78. if p == nil {
  79. return nil, r, ErrInvalidPEMBlock
  80. }
  81. c, err := unmarshalCertificateBlock(p)
  82. if err != nil {
  83. return nil, r, err
  84. }
  85. return c, r, nil
  86. }
  87. // unmarshalCertificateBlock decodes a single PEM block into a certificate.
  88. // It expects a Nebula certificate banner and returns ErrInvalidPEMCertificateBanner otherwise.
  89. func unmarshalCertificateBlock(block *pem.Block) (Certificate, error) {
  90. switch block.Type {
  91. // Implementations must validate the resulting certificate contains valid information
  92. case CertificateBanner:
  93. return unmarshalCertificateV1(block.Bytes, nil)
  94. case CertificateV2Banner:
  95. return unmarshalCertificateV2(block.Bytes, nil, Curve_CURVE25519)
  96. default:
  97. return nil, ErrInvalidPEMCertificateBanner
  98. }
  99. }
  100. func marshalCertPublicKeyToPEM(c Certificate) []byte {
  101. if c.IsCA() {
  102. return MarshalSigningPublicKeyToPEM(c.Curve(), c.PublicKey())
  103. } else {
  104. return MarshalPublicKeyToPEM(c.Curve(), c.PublicKey())
  105. }
  106. }
  107. // MarshalPublicKeyToPEM returns a PEM representation of a public key used for ECDH.
  108. // if your public key came from a certificate, prefer Certificate.PublicKeyPEM() if possible, to avoid mistakes!
  109. func MarshalPublicKeyToPEM(curve Curve, b []byte) []byte {
  110. switch curve {
  111. case Curve_CURVE25519:
  112. return pem.EncodeToMemory(&pem.Block{Type: X25519PublicKeyBanner, Bytes: b})
  113. case Curve_P256:
  114. return pem.EncodeToMemory(&pem.Block{Type: P256PublicKeyBanner, Bytes: b})
  115. default:
  116. return nil
  117. }
  118. }
  119. // MarshalSigningPublicKeyToPEM returns a PEM representation of a public key used for signing.
  120. // if your public key came from a certificate, prefer Certificate.PublicKeyPEM() if possible, to avoid mistakes!
  121. func MarshalSigningPublicKeyToPEM(curve Curve, b []byte) []byte {
  122. switch curve {
  123. case Curve_CURVE25519:
  124. return pem.EncodeToMemory(&pem.Block{Type: Ed25519PublicKeyBanner, Bytes: b})
  125. case Curve_P256:
  126. return pem.EncodeToMemory(&pem.Block{Type: ECDSAP256PublicKeyBanner, Bytes: b})
  127. default:
  128. return nil
  129. }
  130. }
  131. // UnmarshalPublicKeyFromPEM will try to unmarshal the first pem block in a byte array, returning any non
  132. // consumed data or an error on failure. Only key-agreement (ECDH) public key banners are accepted.
  133. // Use UnmarshalSigningPublicKeyFromPEM for Ed25519/ECDSA banners.
  134. func UnmarshalPublicKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
  135. k, r := pem.Decode(b)
  136. if k == nil {
  137. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  138. }
  139. var expectedLen int
  140. var curve Curve
  141. switch k.Type {
  142. case X25519PublicKeyBanner:
  143. expectedLen = 32
  144. curve = Curve_CURVE25519
  145. case P256PublicKeyBanner:
  146. // Uncompressed
  147. expectedLen = 65
  148. curve = Curve_P256
  149. default:
  150. return nil, r, 0, fmt.Errorf("bytes did not contain a proper public key banner")
  151. }
  152. if len(k.Bytes) != expectedLen {
  153. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s public key", expectedLen, curve)
  154. }
  155. return k.Bytes, r, curve, nil
  156. }
  157. // UnmarshalSigningPublicKeyFromPEM will try to unmarshal the first pem block in a byte array, returning any non
  158. // consumed data or an error on failure. Only Ed25519/ECDSA public key banners are accepted.
  159. // Use UnmarshalPublicKeyFromPEM for X25519/P256 (ECDH) banners.
  160. func UnmarshalSigningPublicKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
  161. k, r := pem.Decode(b)
  162. if k == nil {
  163. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  164. }
  165. var expectedLen int
  166. var curve Curve
  167. switch k.Type {
  168. case Ed25519PublicKeyBanner:
  169. expectedLen = 32
  170. curve = Curve_CURVE25519
  171. case ECDSAP256PublicKeyBanner:
  172. // Uncompressed
  173. expectedLen = 65
  174. curve = Curve_P256
  175. default:
  176. return nil, r, 0, fmt.Errorf("bytes did not contain a proper Ed25519/ECDSA public key banner")
  177. }
  178. if len(k.Bytes) != expectedLen {
  179. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s public key", expectedLen, curve)
  180. }
  181. return k.Bytes, r, curve, nil
  182. }
  183. func MarshalPrivateKeyToPEM(curve Curve, b []byte) []byte {
  184. switch curve {
  185. case Curve_CURVE25519:
  186. return pem.EncodeToMemory(&pem.Block{Type: X25519PrivateKeyBanner, Bytes: b})
  187. case Curve_P256:
  188. return pem.EncodeToMemory(&pem.Block{Type: P256PrivateKeyBanner, Bytes: b})
  189. default:
  190. return nil
  191. }
  192. }
  193. func MarshalSigningPrivateKeyToPEM(curve Curve, b []byte) []byte {
  194. switch curve {
  195. case Curve_CURVE25519:
  196. return pem.EncodeToMemory(&pem.Block{Type: Ed25519PrivateKeyBanner, Bytes: b})
  197. case Curve_P256:
  198. return pem.EncodeToMemory(&pem.Block{Type: ECDSAP256PrivateKeyBanner, Bytes: b})
  199. default:
  200. return nil
  201. }
  202. }
  203. // UnmarshalPrivateKeyFromPEM will try to unmarshal the first pem block in a byte array, returning any non
  204. // consumed data or an error on failure
  205. func UnmarshalPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
  206. k, r := pem.Decode(b)
  207. if k == nil {
  208. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  209. }
  210. var expectedLen int
  211. var curve Curve
  212. switch k.Type {
  213. case X25519PrivateKeyBanner:
  214. expectedLen = 32
  215. curve = Curve_CURVE25519
  216. case P256PrivateKeyBanner:
  217. expectedLen = 32
  218. curve = Curve_P256
  219. default:
  220. return nil, r, 0, fmt.Errorf("bytes did not contain a proper private key banner")
  221. }
  222. if len(k.Bytes) != expectedLen {
  223. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s private key", expectedLen, curve)
  224. }
  225. return k.Bytes, r, curve, nil
  226. }
  227. func UnmarshalSigningPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
  228. k, r := pem.Decode(b)
  229. if k == nil {
  230. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  231. }
  232. var curve Curve
  233. switch k.Type {
  234. case EncryptedEd25519PrivateKeyBanner:
  235. return nil, nil, Curve_CURVE25519, ErrPrivateKeyEncrypted
  236. case EncryptedECDSAP256PrivateKeyBanner:
  237. return nil, nil, Curve_P256, ErrPrivateKeyEncrypted
  238. case Ed25519PrivateKeyBanner:
  239. curve = Curve_CURVE25519
  240. if len(k.Bytes) != ed25519.PrivateKeySize {
  241. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid Ed25519 private key", ed25519.PrivateKeySize)
  242. }
  243. case ECDSAP256PrivateKeyBanner:
  244. curve = Curve_P256
  245. if len(k.Bytes) != 32 {
  246. return nil, r, 0, fmt.Errorf("key was not 32 bytes, is invalid ECDSA P256 private key")
  247. }
  248. default:
  249. return nil, r, 0, fmt.Errorf("bytes did not contain a proper Ed25519/ECDSA private key banner")
  250. }
  251. return k.Bytes, r, curve, nil
  252. }