pem.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. package cert
  2. import (
  3. "encoding/hex"
  4. "encoding/pem"
  5. "fmt"
  6. "time"
  7. "golang.org/x/crypto/ed25519"
  8. )
  9. const ( //cert banners
  10. CertificateBanner = "NEBULA CERTIFICATE"
  11. CertificateV2Banner = "NEBULA CERTIFICATE V2"
  12. )
  13. const ( //key-agreement-key banners
  14. X25519PrivateKeyBanner = "NEBULA X25519 PRIVATE KEY"
  15. X25519PublicKeyBanner = "NEBULA X25519 PUBLIC KEY"
  16. P256PrivateKeyBanner = "NEBULA P256 PRIVATE KEY"
  17. P256PublicKeyBanner = "NEBULA P256 PUBLIC KEY"
  18. )
  19. /* including "ECDSA" in the P256 banners is a clue that these keys should be used only for signing */
  20. const ( //signing key banners
  21. EncryptedECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 ENCRYPTED PRIVATE KEY"
  22. ECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 PRIVATE KEY"
  23. ECDSAP256PublicKeyBanner = "NEBULA ECDSA P256 PUBLIC KEY"
  24. EncryptedEd25519PrivateKeyBanner = "NEBULA ED25519 ENCRYPTED PRIVATE KEY"
  25. Ed25519PrivateKeyBanner = "NEBULA ED25519 PRIVATE KEY"
  26. Ed25519PublicKeyBanner = "NEBULA ED25519 PUBLIC KEY"
  27. )
  28. // UnmarshalCertificateFromPEM will try to unmarshal the first pem block in a byte array, returning any non consumed
  29. // data or an error on failure
  30. func UnmarshalCertificateFromPEM(b []byte) (Certificate, []byte, error) {
  31. p, r := pem.Decode(b)
  32. if p == nil {
  33. return nil, r, ErrInvalidPEMBlock
  34. }
  35. var c Certificate
  36. var err error
  37. switch p.Type {
  38. // Implementations must validate the resulting certificate contains valid information
  39. case CertificateBanner:
  40. c, err = unmarshalCertificateV1(p.Bytes, nil)
  41. case CertificateV2Banner:
  42. c, err = unmarshalCertificateV2(p.Bytes, nil, Curve_CURVE25519)
  43. default:
  44. return nil, r, ErrInvalidPEMCertificateBanner
  45. }
  46. if err != nil {
  47. return nil, r, err
  48. }
  49. return c, r, nil
  50. }
  51. func marshalCertPublicKeyToPEM(c Certificate) []byte {
  52. if c.IsCA() {
  53. return MarshalSigningPublicKeyToPEM(c.Curve(), c.PublicKey())
  54. } else {
  55. return MarshalPublicKeyToPEM(c.Curve(), c.PublicKey())
  56. }
  57. }
  58. // MarshalPublicKeyToPEM returns a PEM representation of a public key used for ECDH.
  59. // if your public key came from a certificate, prefer Certificate.PublicKeyPEM() if possible, to avoid mistakes!
  60. func MarshalPublicKeyToPEM(curve Curve, b []byte) []byte {
  61. switch curve {
  62. case Curve_CURVE25519:
  63. return pem.EncodeToMemory(&pem.Block{Type: X25519PublicKeyBanner, Bytes: b})
  64. case Curve_P256:
  65. return pem.EncodeToMemory(&pem.Block{Type: P256PublicKeyBanner, Bytes: b})
  66. default:
  67. return nil
  68. }
  69. }
  70. // MarshalSigningPublicKeyToPEM returns a PEM representation of a public key used for signing.
  71. // if your public key came from a certificate, prefer Certificate.PublicKeyPEM() if possible, to avoid mistakes!
  72. func MarshalSigningPublicKeyToPEM(curve Curve, b []byte) []byte {
  73. switch curve {
  74. case Curve_CURVE25519:
  75. return pem.EncodeToMemory(&pem.Block{Type: Ed25519PublicKeyBanner, Bytes: b})
  76. case Curve_P256:
  77. return pem.EncodeToMemory(&pem.Block{Type: P256PublicKeyBanner, Bytes: b})
  78. default:
  79. return nil
  80. }
  81. }
  82. func UnmarshalPublicKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
  83. k, r := pem.Decode(b)
  84. if k == nil {
  85. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  86. }
  87. var expectedLen int
  88. var curve Curve
  89. switch k.Type {
  90. case X25519PublicKeyBanner, Ed25519PublicKeyBanner:
  91. expectedLen = 32
  92. curve = Curve_CURVE25519
  93. case P256PublicKeyBanner, ECDSAP256PublicKeyBanner:
  94. // Uncompressed
  95. expectedLen = 65
  96. curve = Curve_P256
  97. default:
  98. return nil, r, 0, fmt.Errorf("bytes did not contain a proper public key banner")
  99. }
  100. if len(k.Bytes) != expectedLen {
  101. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s public key", expectedLen, curve)
  102. }
  103. return k.Bytes, r, curve, nil
  104. }
  105. func MarshalPrivateKeyToPEM(curve Curve, b []byte) []byte {
  106. switch curve {
  107. case Curve_CURVE25519:
  108. return pem.EncodeToMemory(&pem.Block{Type: X25519PrivateKeyBanner, Bytes: b})
  109. case Curve_P256:
  110. return pem.EncodeToMemory(&pem.Block{Type: P256PrivateKeyBanner, Bytes: b})
  111. default:
  112. return nil
  113. }
  114. }
  115. func MarshalSigningPrivateKeyToPEM(curve Curve, b []byte) []byte {
  116. switch curve {
  117. case Curve_CURVE25519:
  118. return pem.EncodeToMemory(&pem.Block{Type: Ed25519PrivateKeyBanner, Bytes: b})
  119. case Curve_P256:
  120. return pem.EncodeToMemory(&pem.Block{Type: ECDSAP256PrivateKeyBanner, Bytes: b})
  121. default:
  122. return nil
  123. }
  124. }
  125. // Backward compatibility functions for older API
  126. func MarshalX25519PublicKey(b []byte) []byte {
  127. return MarshalPublicKeyToPEM(Curve_CURVE25519, b)
  128. }
  129. func MarshalX25519PrivateKey(b []byte) []byte {
  130. return MarshalPrivateKeyToPEM(Curve_CURVE25519, b)
  131. }
  132. func MarshalPublicKey(curve Curve, b []byte) []byte {
  133. return MarshalPublicKeyToPEM(curve, b)
  134. }
  135. func MarshalPrivateKey(curve Curve, b []byte) []byte {
  136. return MarshalPrivateKeyToPEM(curve, b)
  137. }
  138. // NebulaCertificate is a compatibility wrapper for the old API
  139. type NebulaCertificate struct {
  140. Details NebulaCertificateDetails
  141. Signature []byte
  142. cert Certificate
  143. }
  144. // NebulaCertificateDetails is a compatibility wrapper for certificate details
  145. type NebulaCertificateDetails struct {
  146. Name string
  147. NotBefore time.Time
  148. NotAfter time.Time
  149. PublicKey []byte
  150. IsCA bool
  151. Issuer []byte
  152. Curve Curve
  153. }
  154. // UnmarshalNebulaCertificateFromPEM provides backward compatibility with the old API
  155. func UnmarshalNebulaCertificateFromPEM(b []byte) (*NebulaCertificate, []byte, error) {
  156. c, rest, err := UnmarshalCertificateFromPEM(b)
  157. if err != nil {
  158. return nil, rest, err
  159. }
  160. issuerBytes, err := func() ([]byte, error) {
  161. issuer := c.Issuer()
  162. if issuer == "" {
  163. return nil, nil
  164. }
  165. decoded, err := hex.DecodeString(issuer)
  166. if err != nil {
  167. return nil, fmt.Errorf("failed to decode issuer fingerprint: %w", err)
  168. }
  169. return decoded, nil
  170. }()
  171. if err != nil {
  172. return nil, rest, err
  173. }
  174. pubKey := c.PublicKey()
  175. if pubKey != nil {
  176. pubKey = append([]byte(nil), pubKey...)
  177. }
  178. sig := c.Signature()
  179. if sig != nil {
  180. sig = append([]byte(nil), sig...)
  181. }
  182. return &NebulaCertificate{
  183. Details: NebulaCertificateDetails{
  184. Name: c.Name(),
  185. NotBefore: c.NotBefore(),
  186. NotAfter: c.NotAfter(),
  187. PublicKey: pubKey,
  188. IsCA: c.IsCA(),
  189. Issuer: issuerBytes,
  190. Curve: c.Curve(),
  191. },
  192. Signature: sig,
  193. cert: c,
  194. }, rest, nil
  195. }
  196. // IssuerString returns the issuer in hex format for compatibility
  197. func (n *NebulaCertificate) IssuerString() string {
  198. if n.Details.Issuer == nil {
  199. return ""
  200. }
  201. return hex.EncodeToString(n.Details.Issuer)
  202. }
  203. // Certificate returns the underlying certificate (read-only)
  204. func (n *NebulaCertificate) Certificate() Certificate {
  205. return n.cert
  206. }
  207. // UnmarshalPrivateKeyFromPEM will try to unmarshal the first pem block in a byte array, returning any non
  208. // consumed data or an error on failure
  209. func UnmarshalPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
  210. k, r := pem.Decode(b)
  211. if k == nil {
  212. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  213. }
  214. var expectedLen int
  215. var curve Curve
  216. switch k.Type {
  217. case X25519PrivateKeyBanner:
  218. expectedLen = 32
  219. curve = Curve_CURVE25519
  220. case P256PrivateKeyBanner:
  221. expectedLen = 32
  222. curve = Curve_P256
  223. default:
  224. return nil, r, 0, fmt.Errorf("bytes did not contain a proper private key banner")
  225. }
  226. if len(k.Bytes) != expectedLen {
  227. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s private key", expectedLen, curve)
  228. }
  229. return k.Bytes, r, curve, nil
  230. }
  231. func UnmarshalSigningPrivateKeyFromPEM(b []byte) ([]byte, []byte, Curve, error) {
  232. k, r := pem.Decode(b)
  233. if k == nil {
  234. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  235. }
  236. var curve Curve
  237. switch k.Type {
  238. case EncryptedEd25519PrivateKeyBanner:
  239. return nil, nil, Curve_CURVE25519, ErrPrivateKeyEncrypted
  240. case EncryptedECDSAP256PrivateKeyBanner:
  241. return nil, nil, Curve_P256, ErrPrivateKeyEncrypted
  242. case Ed25519PrivateKeyBanner:
  243. curve = Curve_CURVE25519
  244. if len(k.Bytes) != ed25519.PrivateKeySize {
  245. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid Ed25519 private key", ed25519.PrivateKeySize)
  246. }
  247. case ECDSAP256PrivateKeyBanner:
  248. curve = Curve_P256
  249. if len(k.Bytes) != 32 {
  250. return nil, r, 0, fmt.Errorf("key was not 32 bytes, is invalid ECDSA P256 private key")
  251. }
  252. default:
  253. return nil, r, 0, fmt.Errorf("bytes did not contain a proper Ed25519/ECDSA private key banner")
  254. }
  255. return k.Bytes, r, curve, nil
  256. }