cert.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. package cert
  2. import (
  3. "bytes"
  4. "crypto/ecdh"
  5. "crypto/ecdsa"
  6. "crypto/ed25519"
  7. "crypto/elliptic"
  8. "crypto/rand"
  9. "crypto/sha256"
  10. "encoding/binary"
  11. "encoding/hex"
  12. "encoding/json"
  13. "encoding/pem"
  14. "errors"
  15. "fmt"
  16. "math"
  17. "math/big"
  18. "net"
  19. "sync/atomic"
  20. "time"
  21. "golang.org/x/crypto/curve25519"
  22. "google.golang.org/protobuf/proto"
  23. )
  24. const publicKeyLen = 32
  25. const (
  26. CertBanner = "NEBULA CERTIFICATE"
  27. X25519PrivateKeyBanner = "NEBULA X25519 PRIVATE KEY"
  28. X25519PublicKeyBanner = "NEBULA X25519 PUBLIC KEY"
  29. EncryptedEd25519PrivateKeyBanner = "NEBULA ED25519 ENCRYPTED PRIVATE KEY"
  30. Ed25519PrivateKeyBanner = "NEBULA ED25519 PRIVATE KEY"
  31. Ed25519PublicKeyBanner = "NEBULA ED25519 PUBLIC KEY"
  32. P256PrivateKeyBanner = "NEBULA P256 PRIVATE KEY"
  33. P256PublicKeyBanner = "NEBULA P256 PUBLIC KEY"
  34. EncryptedECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 ENCRYPTED PRIVATE KEY"
  35. ECDSAP256PrivateKeyBanner = "NEBULA ECDSA P256 PRIVATE KEY"
  36. )
  37. type NebulaCertificate struct {
  38. Details NebulaCertificateDetails
  39. Signature []byte
  40. // the cached hex string of the calculated sha256sum
  41. // for VerifyWithCache
  42. sha256sum atomic.Pointer[string]
  43. // the cached public key bytes if they were verified as the signer
  44. // for VerifyWithCache
  45. signatureVerified atomic.Pointer[[]byte]
  46. }
  47. type NebulaCertificateDetails struct {
  48. Name string
  49. Ips []*net.IPNet
  50. Subnets []*net.IPNet
  51. Groups []string
  52. NotBefore time.Time
  53. NotAfter time.Time
  54. PublicKey []byte
  55. IsCA bool
  56. Issuer string
  57. // Map of groups for faster lookup
  58. InvertedGroups map[string]struct{}
  59. Curve Curve
  60. }
  61. type NebulaEncryptedData struct {
  62. EncryptionMetadata NebulaEncryptionMetadata
  63. Ciphertext []byte
  64. }
  65. type NebulaEncryptionMetadata struct {
  66. EncryptionAlgorithm string
  67. Argon2Parameters Argon2Parameters
  68. }
  69. type m map[string]interface{}
  70. // Returned if we try to unmarshal an encrypted private key without a passphrase
  71. var ErrPrivateKeyEncrypted = errors.New("private key must be decrypted")
  72. // UnmarshalNebulaCertificate will unmarshal a protobuf byte representation of a nebula cert
  73. func UnmarshalNebulaCertificate(b []byte) (*NebulaCertificate, error) {
  74. if len(b) == 0 {
  75. return nil, fmt.Errorf("nil byte array")
  76. }
  77. var rc RawNebulaCertificate
  78. err := proto.Unmarshal(b, &rc)
  79. if err != nil {
  80. return nil, err
  81. }
  82. if rc.Details == nil {
  83. return nil, fmt.Errorf("encoded Details was nil")
  84. }
  85. if len(rc.Details.Ips)%2 != 0 {
  86. return nil, fmt.Errorf("encoded IPs should be in pairs, an odd number was found")
  87. }
  88. if len(rc.Details.Subnets)%2 != 0 {
  89. return nil, fmt.Errorf("encoded Subnets should be in pairs, an odd number was found")
  90. }
  91. nc := NebulaCertificate{
  92. Details: NebulaCertificateDetails{
  93. Name: rc.Details.Name,
  94. Groups: make([]string, len(rc.Details.Groups)),
  95. Ips: make([]*net.IPNet, len(rc.Details.Ips)/2),
  96. Subnets: make([]*net.IPNet, len(rc.Details.Subnets)/2),
  97. NotBefore: time.Unix(rc.Details.NotBefore, 0),
  98. NotAfter: time.Unix(rc.Details.NotAfter, 0),
  99. PublicKey: make([]byte, len(rc.Details.PublicKey)),
  100. IsCA: rc.Details.IsCA,
  101. InvertedGroups: make(map[string]struct{}),
  102. Curve: rc.Details.Curve,
  103. },
  104. Signature: make([]byte, len(rc.Signature)),
  105. }
  106. copy(nc.Signature, rc.Signature)
  107. copy(nc.Details.Groups, rc.Details.Groups)
  108. nc.Details.Issuer = hex.EncodeToString(rc.Details.Issuer)
  109. if len(rc.Details.PublicKey) < publicKeyLen {
  110. return nil, fmt.Errorf("Public key was fewer than 32 bytes; %v", len(rc.Details.PublicKey))
  111. }
  112. copy(nc.Details.PublicKey, rc.Details.PublicKey)
  113. for i, rawIp := range rc.Details.Ips {
  114. if i%2 == 0 {
  115. nc.Details.Ips[i/2] = &net.IPNet{IP: int2ip(rawIp)}
  116. } else {
  117. nc.Details.Ips[i/2].Mask = net.IPMask(int2ip(rawIp))
  118. }
  119. }
  120. for i, rawIp := range rc.Details.Subnets {
  121. if i%2 == 0 {
  122. nc.Details.Subnets[i/2] = &net.IPNet{IP: int2ip(rawIp)}
  123. } else {
  124. nc.Details.Subnets[i/2].Mask = net.IPMask(int2ip(rawIp))
  125. }
  126. }
  127. for _, g := range rc.Details.Groups {
  128. nc.Details.InvertedGroups[g] = struct{}{}
  129. }
  130. return &nc, nil
  131. }
  132. // UnmarshalNebulaCertificateFromPEM will unmarshal the first pem block in a byte array, returning any non consumed data
  133. // or an error on failure
  134. func UnmarshalNebulaCertificateFromPEM(b []byte) (*NebulaCertificate, []byte, error) {
  135. p, r := pem.Decode(b)
  136. if p == nil {
  137. return nil, r, fmt.Errorf("input did not contain a valid PEM encoded block")
  138. }
  139. if p.Type != CertBanner {
  140. return nil, r, fmt.Errorf("bytes did not contain a proper nebula certificate banner")
  141. }
  142. nc, err := UnmarshalNebulaCertificate(p.Bytes)
  143. return nc, r, err
  144. }
  145. func MarshalPrivateKey(curve Curve, b []byte) []byte {
  146. switch curve {
  147. case Curve_CURVE25519:
  148. return pem.EncodeToMemory(&pem.Block{Type: X25519PrivateKeyBanner, Bytes: b})
  149. case Curve_P256:
  150. return pem.EncodeToMemory(&pem.Block{Type: P256PrivateKeyBanner, Bytes: b})
  151. default:
  152. return nil
  153. }
  154. }
  155. func MarshalSigningPrivateKey(curve Curve, b []byte) []byte {
  156. switch curve {
  157. case Curve_CURVE25519:
  158. return pem.EncodeToMemory(&pem.Block{Type: Ed25519PrivateKeyBanner, Bytes: b})
  159. case Curve_P256:
  160. return pem.EncodeToMemory(&pem.Block{Type: ECDSAP256PrivateKeyBanner, Bytes: b})
  161. default:
  162. return nil
  163. }
  164. }
  165. // MarshalX25519PrivateKey is a simple helper to PEM encode an X25519 private key
  166. func MarshalX25519PrivateKey(b []byte) []byte {
  167. return pem.EncodeToMemory(&pem.Block{Type: X25519PrivateKeyBanner, Bytes: b})
  168. }
  169. // MarshalEd25519PrivateKey is a simple helper to PEM encode an Ed25519 private key
  170. func MarshalEd25519PrivateKey(key ed25519.PrivateKey) []byte {
  171. return pem.EncodeToMemory(&pem.Block{Type: Ed25519PrivateKeyBanner, Bytes: key})
  172. }
  173. func UnmarshalPrivateKey(b []byte) ([]byte, []byte, Curve, error) {
  174. k, r := pem.Decode(b)
  175. if k == nil {
  176. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  177. }
  178. var expectedLen int
  179. var curve Curve
  180. switch k.Type {
  181. case X25519PrivateKeyBanner:
  182. expectedLen = 32
  183. curve = Curve_CURVE25519
  184. case P256PrivateKeyBanner:
  185. expectedLen = 32
  186. curve = Curve_P256
  187. default:
  188. return nil, r, 0, fmt.Errorf("bytes did not contain a proper nebula private key banner")
  189. }
  190. if len(k.Bytes) != expectedLen {
  191. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s private key", expectedLen, curve)
  192. }
  193. return k.Bytes, r, curve, nil
  194. }
  195. func UnmarshalSigningPrivateKey(b []byte) ([]byte, []byte, Curve, error) {
  196. k, r := pem.Decode(b)
  197. if k == nil {
  198. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  199. }
  200. var curve Curve
  201. switch k.Type {
  202. case EncryptedEd25519PrivateKeyBanner:
  203. return nil, nil, Curve_CURVE25519, ErrPrivateKeyEncrypted
  204. case EncryptedECDSAP256PrivateKeyBanner:
  205. return nil, nil, Curve_P256, ErrPrivateKeyEncrypted
  206. case Ed25519PrivateKeyBanner:
  207. curve = Curve_CURVE25519
  208. if len(k.Bytes) != ed25519.PrivateKeySize {
  209. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid Ed25519 private key", ed25519.PrivateKeySize)
  210. }
  211. case ECDSAP256PrivateKeyBanner:
  212. curve = Curve_P256
  213. if len(k.Bytes) != 32 {
  214. return nil, r, 0, fmt.Errorf("key was not 32 bytes, is invalid ECDSA P256 private key")
  215. }
  216. default:
  217. return nil, r, 0, fmt.Errorf("bytes did not contain a proper nebula Ed25519/ECDSA private key banner")
  218. }
  219. return k.Bytes, r, curve, nil
  220. }
  221. // EncryptAndMarshalSigningPrivateKey is a simple helper to encrypt and PEM encode a private key
  222. func EncryptAndMarshalSigningPrivateKey(curve Curve, b []byte, passphrase []byte, kdfParams *Argon2Parameters) ([]byte, error) {
  223. ciphertext, err := aes256Encrypt(passphrase, kdfParams, b)
  224. if err != nil {
  225. return nil, err
  226. }
  227. b, err = proto.Marshal(&RawNebulaEncryptedData{
  228. EncryptionMetadata: &RawNebulaEncryptionMetadata{
  229. EncryptionAlgorithm: "AES-256-GCM",
  230. Argon2Parameters: &RawNebulaArgon2Parameters{
  231. Version: kdfParams.version,
  232. Memory: kdfParams.Memory,
  233. Parallelism: uint32(kdfParams.Parallelism),
  234. Iterations: kdfParams.Iterations,
  235. Salt: kdfParams.salt,
  236. },
  237. },
  238. Ciphertext: ciphertext,
  239. })
  240. switch curve {
  241. case Curve_CURVE25519:
  242. return pem.EncodeToMemory(&pem.Block{Type: EncryptedEd25519PrivateKeyBanner, Bytes: b}), nil
  243. case Curve_P256:
  244. return pem.EncodeToMemory(&pem.Block{Type: EncryptedECDSAP256PrivateKeyBanner, Bytes: b}), nil
  245. default:
  246. return nil, fmt.Errorf("invalid curve: %v", curve)
  247. }
  248. }
  249. // UnmarshalX25519PrivateKey will try to pem decode an X25519 private key, returning any other bytes b
  250. // or an error on failure
  251. func UnmarshalX25519PrivateKey(b []byte) ([]byte, []byte, error) {
  252. k, r := pem.Decode(b)
  253. if k == nil {
  254. return nil, r, fmt.Errorf("input did not contain a valid PEM encoded block")
  255. }
  256. if k.Type != X25519PrivateKeyBanner {
  257. return nil, r, fmt.Errorf("bytes did not contain a proper nebula X25519 private key banner")
  258. }
  259. if len(k.Bytes) != publicKeyLen {
  260. return nil, r, fmt.Errorf("key was not 32 bytes, is invalid X25519 private key")
  261. }
  262. return k.Bytes, r, nil
  263. }
  264. // UnmarshalEd25519PrivateKey will try to pem decode an Ed25519 private key, returning any other bytes b
  265. // or an error on failure
  266. func UnmarshalEd25519PrivateKey(b []byte) (ed25519.PrivateKey, []byte, error) {
  267. k, r := pem.Decode(b)
  268. if k == nil {
  269. return nil, r, fmt.Errorf("input did not contain a valid PEM encoded block")
  270. }
  271. if k.Type == EncryptedEd25519PrivateKeyBanner {
  272. return nil, r, ErrPrivateKeyEncrypted
  273. } else if k.Type != Ed25519PrivateKeyBanner {
  274. return nil, r, fmt.Errorf("bytes did not contain a proper nebula Ed25519 private key banner")
  275. }
  276. if len(k.Bytes) != ed25519.PrivateKeySize {
  277. return nil, r, fmt.Errorf("key was not 64 bytes, is invalid ed25519 private key")
  278. }
  279. return k.Bytes, r, nil
  280. }
  281. // UnmarshalNebulaCertificate will unmarshal a protobuf byte representation of a nebula cert into its
  282. // protobuf-generated struct.
  283. func UnmarshalNebulaEncryptedData(b []byte) (*NebulaEncryptedData, error) {
  284. if len(b) == 0 {
  285. return nil, fmt.Errorf("nil byte array")
  286. }
  287. var rned RawNebulaEncryptedData
  288. err := proto.Unmarshal(b, &rned)
  289. if err != nil {
  290. return nil, err
  291. }
  292. if rned.EncryptionMetadata == nil {
  293. return nil, fmt.Errorf("encoded EncryptionMetadata was nil")
  294. }
  295. if rned.EncryptionMetadata.Argon2Parameters == nil {
  296. return nil, fmt.Errorf("encoded Argon2Parameters was nil")
  297. }
  298. params, err := unmarshalArgon2Parameters(rned.EncryptionMetadata.Argon2Parameters)
  299. if err != nil {
  300. return nil, err
  301. }
  302. ned := NebulaEncryptedData{
  303. EncryptionMetadata: NebulaEncryptionMetadata{
  304. EncryptionAlgorithm: rned.EncryptionMetadata.EncryptionAlgorithm,
  305. Argon2Parameters: *params,
  306. },
  307. Ciphertext: rned.Ciphertext,
  308. }
  309. return &ned, nil
  310. }
  311. func unmarshalArgon2Parameters(params *RawNebulaArgon2Parameters) (*Argon2Parameters, error) {
  312. if params.Version < math.MinInt32 || params.Version > math.MaxInt32 {
  313. return nil, fmt.Errorf("Argon2Parameters Version must be at least %d and no more than %d", math.MinInt32, math.MaxInt32)
  314. }
  315. if params.Memory <= 0 || params.Memory > math.MaxUint32 {
  316. return nil, fmt.Errorf("Argon2Parameters Memory must be be greater than 0 and no more than %d KiB", uint32(math.MaxUint32))
  317. }
  318. if params.Parallelism <= 0 || params.Parallelism > math.MaxUint8 {
  319. return nil, fmt.Errorf("Argon2Parameters Parallelism must be be greater than 0 and no more than %d", math.MaxUint8)
  320. }
  321. if params.Iterations <= 0 || params.Iterations > math.MaxUint32 {
  322. return nil, fmt.Errorf("-argon-iterations must be be greater than 0 and no more than %d", uint32(math.MaxUint32))
  323. }
  324. return &Argon2Parameters{
  325. version: rune(params.Version),
  326. Memory: uint32(params.Memory),
  327. Parallelism: uint8(params.Parallelism),
  328. Iterations: uint32(params.Iterations),
  329. salt: params.Salt,
  330. }, nil
  331. }
  332. // DecryptAndUnmarshalSigningPrivateKey will try to pem decode and decrypt an Ed25519/ECDSA private key with
  333. // the given passphrase, returning any other bytes b or an error on failure
  334. func DecryptAndUnmarshalSigningPrivateKey(passphrase, b []byte) (Curve, []byte, []byte, error) {
  335. var curve Curve
  336. k, r := pem.Decode(b)
  337. if k == nil {
  338. return curve, nil, r, fmt.Errorf("input did not contain a valid PEM encoded block")
  339. }
  340. switch k.Type {
  341. case EncryptedEd25519PrivateKeyBanner:
  342. curve = Curve_CURVE25519
  343. case EncryptedECDSAP256PrivateKeyBanner:
  344. curve = Curve_P256
  345. default:
  346. return curve, nil, r, fmt.Errorf("bytes did not contain a proper nebula encrypted Ed25519/ECDSA private key banner")
  347. }
  348. ned, err := UnmarshalNebulaEncryptedData(k.Bytes)
  349. if err != nil {
  350. return curve, nil, r, err
  351. }
  352. var bytes []byte
  353. switch ned.EncryptionMetadata.EncryptionAlgorithm {
  354. case "AES-256-GCM":
  355. bytes, err = aes256Decrypt(passphrase, &ned.EncryptionMetadata.Argon2Parameters, ned.Ciphertext)
  356. if err != nil {
  357. return curve, nil, r, err
  358. }
  359. default:
  360. return curve, nil, r, fmt.Errorf("unsupported encryption algorithm: %s", ned.EncryptionMetadata.EncryptionAlgorithm)
  361. }
  362. switch curve {
  363. case Curve_CURVE25519:
  364. if len(bytes) != ed25519.PrivateKeySize {
  365. return curve, nil, r, fmt.Errorf("key was not %d bytes, is invalid ed25519 private key", ed25519.PrivateKeySize)
  366. }
  367. case Curve_P256:
  368. if len(bytes) != 32 {
  369. return curve, nil, r, fmt.Errorf("key was not 32 bytes, is invalid ECDSA P256 private key")
  370. }
  371. }
  372. return curve, bytes, r, nil
  373. }
  374. func MarshalPublicKey(curve Curve, b []byte) []byte {
  375. switch curve {
  376. case Curve_CURVE25519:
  377. return pem.EncodeToMemory(&pem.Block{Type: X25519PublicKeyBanner, Bytes: b})
  378. case Curve_P256:
  379. return pem.EncodeToMemory(&pem.Block{Type: P256PublicKeyBanner, Bytes: b})
  380. default:
  381. return nil
  382. }
  383. }
  384. // MarshalX25519PublicKey is a simple helper to PEM encode an X25519 public key
  385. func MarshalX25519PublicKey(b []byte) []byte {
  386. return pem.EncodeToMemory(&pem.Block{Type: X25519PublicKeyBanner, Bytes: b})
  387. }
  388. // MarshalEd25519PublicKey is a simple helper to PEM encode an Ed25519 public key
  389. func MarshalEd25519PublicKey(key ed25519.PublicKey) []byte {
  390. return pem.EncodeToMemory(&pem.Block{Type: Ed25519PublicKeyBanner, Bytes: key})
  391. }
  392. func UnmarshalPublicKey(b []byte) ([]byte, []byte, Curve, error) {
  393. k, r := pem.Decode(b)
  394. if k == nil {
  395. return nil, r, 0, fmt.Errorf("input did not contain a valid PEM encoded block")
  396. }
  397. var expectedLen int
  398. var curve Curve
  399. switch k.Type {
  400. case X25519PublicKeyBanner:
  401. expectedLen = 32
  402. curve = Curve_CURVE25519
  403. case P256PublicKeyBanner:
  404. // Uncompressed
  405. expectedLen = 65
  406. curve = Curve_P256
  407. default:
  408. return nil, r, 0, fmt.Errorf("bytes did not contain a proper nebula public key banner")
  409. }
  410. if len(k.Bytes) != expectedLen {
  411. return nil, r, 0, fmt.Errorf("key was not %d bytes, is invalid %s public key", expectedLen, curve)
  412. }
  413. return k.Bytes, r, curve, nil
  414. }
  415. // UnmarshalX25519PublicKey will try to pem decode an X25519 public key, returning any other bytes b
  416. // or an error on failure
  417. func UnmarshalX25519PublicKey(b []byte) ([]byte, []byte, error) {
  418. k, r := pem.Decode(b)
  419. if k == nil {
  420. return nil, r, fmt.Errorf("input did not contain a valid PEM encoded block")
  421. }
  422. if k.Type != X25519PublicKeyBanner {
  423. return nil, r, fmt.Errorf("bytes did not contain a proper nebula X25519 public key banner")
  424. }
  425. if len(k.Bytes) != publicKeyLen {
  426. return nil, r, fmt.Errorf("key was not 32 bytes, is invalid X25519 public key")
  427. }
  428. return k.Bytes, r, nil
  429. }
  430. // UnmarshalEd25519PublicKey will try to pem decode an Ed25519 public key, returning any other bytes b
  431. // or an error on failure
  432. func UnmarshalEd25519PublicKey(b []byte) (ed25519.PublicKey, []byte, error) {
  433. k, r := pem.Decode(b)
  434. if k == nil {
  435. return nil, r, fmt.Errorf("input did not contain a valid PEM encoded block")
  436. }
  437. if k.Type != Ed25519PublicKeyBanner {
  438. return nil, r, fmt.Errorf("bytes did not contain a proper nebula Ed25519 public key banner")
  439. }
  440. if len(k.Bytes) != ed25519.PublicKeySize {
  441. return nil, r, fmt.Errorf("key was not 32 bytes, is invalid ed25519 public key")
  442. }
  443. return k.Bytes, r, nil
  444. }
  445. // Sign signs a nebula cert with the provided private key
  446. func (nc *NebulaCertificate) Sign(curve Curve, key []byte) error {
  447. if curve != nc.Details.Curve {
  448. return fmt.Errorf("curve in cert and private key supplied don't match")
  449. }
  450. b, err := proto.Marshal(nc.getRawDetails())
  451. if err != nil {
  452. return err
  453. }
  454. var sig []byte
  455. switch curve {
  456. case Curve_CURVE25519:
  457. signer := ed25519.PrivateKey(key)
  458. sig = ed25519.Sign(signer, b)
  459. case Curve_P256:
  460. signer := &ecdsa.PrivateKey{
  461. PublicKey: ecdsa.PublicKey{
  462. Curve: elliptic.P256(),
  463. },
  464. // ref: https://github.com/golang/go/blob/go1.19/src/crypto/x509/sec1.go#L95
  465. D: new(big.Int).SetBytes(key),
  466. }
  467. // ref: https://github.com/golang/go/blob/go1.19/src/crypto/x509/sec1.go#L119
  468. signer.X, signer.Y = signer.Curve.ScalarBaseMult(key)
  469. // We need to hash first for ECDSA
  470. // - https://pkg.go.dev/crypto/ecdsa#SignASN1
  471. hashed := sha256.Sum256(b)
  472. sig, err = ecdsa.SignASN1(rand.Reader, signer, hashed[:])
  473. if err != nil {
  474. return err
  475. }
  476. default:
  477. return fmt.Errorf("invalid curve: %s", nc.Details.Curve)
  478. }
  479. nc.Signature = sig
  480. return nil
  481. }
  482. // CheckSignature verifies the signature against the provided public key
  483. func (nc *NebulaCertificate) CheckSignature(key []byte) bool {
  484. b, err := proto.Marshal(nc.getRawDetails())
  485. if err != nil {
  486. return false
  487. }
  488. switch nc.Details.Curve {
  489. case Curve_CURVE25519:
  490. return ed25519.Verify(ed25519.PublicKey(key), b, nc.Signature)
  491. case Curve_P256:
  492. x, y := elliptic.Unmarshal(elliptic.P256(), key)
  493. pubKey := &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}
  494. hashed := sha256.Sum256(b)
  495. return ecdsa.VerifyASN1(pubKey, hashed[:], nc.Signature)
  496. default:
  497. return false
  498. }
  499. }
  500. // NOTE: This uses an internal cache that will not be invalidated automatically
  501. // if you manually change any fields in the NebulaCertificate.
  502. func (nc *NebulaCertificate) checkSignatureWithCache(key []byte, useCache bool) bool {
  503. if !useCache {
  504. return nc.CheckSignature(key)
  505. }
  506. if v := nc.signatureVerified.Load(); v != nil {
  507. return bytes.Equal(*v, key)
  508. }
  509. verified := nc.CheckSignature(key)
  510. if verified {
  511. keyCopy := make([]byte, len(key))
  512. copy(keyCopy, key)
  513. nc.signatureVerified.Store(&keyCopy)
  514. }
  515. return verified
  516. }
  517. // Expired will return true if the nebula cert is too young or too old compared to the provided time, otherwise false
  518. func (nc *NebulaCertificate) Expired(t time.Time) bool {
  519. return nc.Details.NotBefore.After(t) || nc.Details.NotAfter.Before(t)
  520. }
  521. // Verify will ensure a certificate is good in all respects (expiry, group membership, signature, cert blocklist, etc)
  522. func (nc *NebulaCertificate) Verify(t time.Time, ncp *NebulaCAPool) (bool, error) {
  523. return nc.verify(t, ncp, false)
  524. }
  525. // VerifyWithCache will ensure a certificate is good in all respects (expiry, group membership, signature, cert blocklist, etc)
  526. //
  527. // NOTE: This uses an internal cache that will not be invalidated automatically
  528. // if you manually change any fields in the NebulaCertificate.
  529. func (nc *NebulaCertificate) VerifyWithCache(t time.Time, ncp *NebulaCAPool) (bool, error) {
  530. return nc.verify(t, ncp, true)
  531. }
  532. // ResetCache resets the cache used by VerifyWithCache.
  533. func (nc *NebulaCertificate) ResetCache() {
  534. nc.sha256sum.Store(nil)
  535. nc.signatureVerified.Store(nil)
  536. }
  537. // Verify will ensure a certificate is good in all respects (expiry, group membership, signature, cert blocklist, etc)
  538. func (nc *NebulaCertificate) verify(t time.Time, ncp *NebulaCAPool, useCache bool) (bool, error) {
  539. if ncp.isBlocklistedWithCache(nc, useCache) {
  540. return false, ErrBlockListed
  541. }
  542. signer, err := ncp.GetCAForCert(nc)
  543. if err != nil {
  544. return false, err
  545. }
  546. if signer.Expired(t) {
  547. return false, ErrRootExpired
  548. }
  549. if nc.Expired(t) {
  550. return false, ErrExpired
  551. }
  552. if !nc.checkSignatureWithCache(signer.Details.PublicKey, useCache) {
  553. return false, ErrSignatureMismatch
  554. }
  555. if err := nc.CheckRootConstrains(signer); err != nil {
  556. return false, err
  557. }
  558. return true, nil
  559. }
  560. // CheckRootConstrains returns an error if the certificate violates constraints set on the root (groups, ips, subnets)
  561. func (nc *NebulaCertificate) CheckRootConstrains(signer *NebulaCertificate) error {
  562. // Make sure this cert wasn't valid before the root
  563. if signer.Details.NotAfter.Before(nc.Details.NotAfter) {
  564. return fmt.Errorf("certificate expires after signing certificate")
  565. }
  566. // Make sure this cert isn't valid after the root
  567. if signer.Details.NotBefore.After(nc.Details.NotBefore) {
  568. return fmt.Errorf("certificate is valid before the signing certificate")
  569. }
  570. // If the signer has a limited set of groups make sure the cert only contains a subset
  571. if len(signer.Details.InvertedGroups) > 0 {
  572. for _, g := range nc.Details.Groups {
  573. if _, ok := signer.Details.InvertedGroups[g]; !ok {
  574. return fmt.Errorf("certificate contained a group not present on the signing ca: %s", g)
  575. }
  576. }
  577. }
  578. // If the signer has a limited set of ip ranges to issue from make sure the cert only contains a subset
  579. if len(signer.Details.Ips) > 0 {
  580. for _, ip := range nc.Details.Ips {
  581. if !netMatch(ip, signer.Details.Ips) {
  582. return fmt.Errorf("certificate contained an ip assignment outside the limitations of the signing ca: %s", ip.String())
  583. }
  584. }
  585. }
  586. // If the signer has a limited set of subnet ranges to issue from make sure the cert only contains a subset
  587. if len(signer.Details.Subnets) > 0 {
  588. for _, subnet := range nc.Details.Subnets {
  589. if !netMatch(subnet, signer.Details.Subnets) {
  590. return fmt.Errorf("certificate contained a subnet assignment outside the limitations of the signing ca: %s", subnet)
  591. }
  592. }
  593. }
  594. return nil
  595. }
  596. // VerifyPrivateKey checks that the public key in the Nebula certificate and a supplied private key match
  597. func (nc *NebulaCertificate) VerifyPrivateKey(curve Curve, key []byte) error {
  598. if curve != nc.Details.Curve {
  599. return fmt.Errorf("curve in cert and private key supplied don't match")
  600. }
  601. if nc.Details.IsCA {
  602. switch curve {
  603. case Curve_CURVE25519:
  604. // the call to PublicKey below will panic slice bounds out of range otherwise
  605. if len(key) != ed25519.PrivateKeySize {
  606. return fmt.Errorf("key was not 64 bytes, is invalid ed25519 private key")
  607. }
  608. if !ed25519.PublicKey(nc.Details.PublicKey).Equal(ed25519.PrivateKey(key).Public()) {
  609. return fmt.Errorf("public key in cert and private key supplied don't match")
  610. }
  611. case Curve_P256:
  612. privkey, err := ecdh.P256().NewPrivateKey(key)
  613. if err != nil {
  614. return fmt.Errorf("cannot parse private key as P256")
  615. }
  616. pub := privkey.PublicKey().Bytes()
  617. if !bytes.Equal(pub, nc.Details.PublicKey) {
  618. return fmt.Errorf("public key in cert and private key supplied don't match")
  619. }
  620. default:
  621. return fmt.Errorf("invalid curve: %s", curve)
  622. }
  623. return nil
  624. }
  625. var pub []byte
  626. switch curve {
  627. case Curve_CURVE25519:
  628. var err error
  629. pub, err = curve25519.X25519(key, curve25519.Basepoint)
  630. if err != nil {
  631. return err
  632. }
  633. case Curve_P256:
  634. privkey, err := ecdh.P256().NewPrivateKey(key)
  635. if err != nil {
  636. return err
  637. }
  638. pub = privkey.PublicKey().Bytes()
  639. default:
  640. return fmt.Errorf("invalid curve: %s", curve)
  641. }
  642. if !bytes.Equal(pub, nc.Details.PublicKey) {
  643. return fmt.Errorf("public key in cert and private key supplied don't match")
  644. }
  645. return nil
  646. }
  647. // String will return a pretty printed representation of a nebula cert
  648. func (nc *NebulaCertificate) String() string {
  649. if nc == nil {
  650. return "NebulaCertificate {}\n"
  651. }
  652. s := "NebulaCertificate {\n"
  653. s += "\tDetails {\n"
  654. s += fmt.Sprintf("\t\tName: %v\n", nc.Details.Name)
  655. if len(nc.Details.Ips) > 0 {
  656. s += "\t\tIps: [\n"
  657. for _, ip := range nc.Details.Ips {
  658. s += fmt.Sprintf("\t\t\t%v\n", ip.String())
  659. }
  660. s += "\t\t]\n"
  661. } else {
  662. s += "\t\tIps: []\n"
  663. }
  664. if len(nc.Details.Subnets) > 0 {
  665. s += "\t\tSubnets: [\n"
  666. for _, ip := range nc.Details.Subnets {
  667. s += fmt.Sprintf("\t\t\t%v\n", ip.String())
  668. }
  669. s += "\t\t]\n"
  670. } else {
  671. s += "\t\tSubnets: []\n"
  672. }
  673. if len(nc.Details.Groups) > 0 {
  674. s += "\t\tGroups: [\n"
  675. for _, g := range nc.Details.Groups {
  676. s += fmt.Sprintf("\t\t\t\"%v\"\n", g)
  677. }
  678. s += "\t\t]\n"
  679. } else {
  680. s += "\t\tGroups: []\n"
  681. }
  682. s += fmt.Sprintf("\t\tNot before: %v\n", nc.Details.NotBefore)
  683. s += fmt.Sprintf("\t\tNot After: %v\n", nc.Details.NotAfter)
  684. s += fmt.Sprintf("\t\tIs CA: %v\n", nc.Details.IsCA)
  685. s += fmt.Sprintf("\t\tIssuer: %s\n", nc.Details.Issuer)
  686. s += fmt.Sprintf("\t\tPublic key: %x\n", nc.Details.PublicKey)
  687. s += fmt.Sprintf("\t\tCurve: %s\n", nc.Details.Curve)
  688. s += "\t}\n"
  689. fp, err := nc.Sha256Sum()
  690. if err == nil {
  691. s += fmt.Sprintf("\tFingerprint: %s\n", fp)
  692. }
  693. s += fmt.Sprintf("\tSignature: %x\n", nc.Signature)
  694. s += "}"
  695. return s
  696. }
  697. // getRawDetails marshals the raw details into protobuf ready struct
  698. func (nc *NebulaCertificate) getRawDetails() *RawNebulaCertificateDetails {
  699. rd := &RawNebulaCertificateDetails{
  700. Name: nc.Details.Name,
  701. Groups: nc.Details.Groups,
  702. NotBefore: nc.Details.NotBefore.Unix(),
  703. NotAfter: nc.Details.NotAfter.Unix(),
  704. PublicKey: make([]byte, len(nc.Details.PublicKey)),
  705. IsCA: nc.Details.IsCA,
  706. Curve: nc.Details.Curve,
  707. }
  708. for _, ipNet := range nc.Details.Ips {
  709. rd.Ips = append(rd.Ips, ip2int(ipNet.IP), ip2int(ipNet.Mask))
  710. }
  711. for _, ipNet := range nc.Details.Subnets {
  712. rd.Subnets = append(rd.Subnets, ip2int(ipNet.IP), ip2int(ipNet.Mask))
  713. }
  714. copy(rd.PublicKey, nc.Details.PublicKey[:])
  715. // I know, this is terrible
  716. rd.Issuer, _ = hex.DecodeString(nc.Details.Issuer)
  717. return rd
  718. }
  719. // Marshal will marshal a nebula cert into a protobuf byte array
  720. func (nc *NebulaCertificate) Marshal() ([]byte, error) {
  721. rc := RawNebulaCertificate{
  722. Details: nc.getRawDetails(),
  723. Signature: nc.Signature,
  724. }
  725. return proto.Marshal(&rc)
  726. }
  727. // MarshalToPEM will marshal a nebula cert into a protobuf byte array and pem encode the result
  728. func (nc *NebulaCertificate) MarshalToPEM() ([]byte, error) {
  729. b, err := nc.Marshal()
  730. if err != nil {
  731. return nil, err
  732. }
  733. return pem.EncodeToMemory(&pem.Block{Type: CertBanner, Bytes: b}), nil
  734. }
  735. // Sha256Sum calculates a sha-256 sum of the marshaled certificate
  736. func (nc *NebulaCertificate) Sha256Sum() (string, error) {
  737. b, err := nc.Marshal()
  738. if err != nil {
  739. return "", err
  740. }
  741. sum := sha256.Sum256(b)
  742. return hex.EncodeToString(sum[:]), nil
  743. }
  744. // NOTE: This uses an internal cache that will not be invalidated automatically
  745. // if you manually change any fields in the NebulaCertificate.
  746. func (nc *NebulaCertificate) sha256SumWithCache(useCache bool) (string, error) {
  747. if !useCache {
  748. return nc.Sha256Sum()
  749. }
  750. if s := nc.sha256sum.Load(); s != nil {
  751. return *s, nil
  752. }
  753. s, err := nc.Sha256Sum()
  754. if err != nil {
  755. return s, err
  756. }
  757. nc.sha256sum.Store(&s)
  758. return s, nil
  759. }
  760. func (nc *NebulaCertificate) MarshalJSON() ([]byte, error) {
  761. toString := func(ips []*net.IPNet) []string {
  762. s := []string{}
  763. for _, ip := range ips {
  764. s = append(s, ip.String())
  765. }
  766. return s
  767. }
  768. fp, _ := nc.Sha256Sum()
  769. jc := m{
  770. "details": m{
  771. "name": nc.Details.Name,
  772. "ips": toString(nc.Details.Ips),
  773. "subnets": toString(nc.Details.Subnets),
  774. "groups": nc.Details.Groups,
  775. "notBefore": nc.Details.NotBefore,
  776. "notAfter": nc.Details.NotAfter,
  777. "publicKey": fmt.Sprintf("%x", nc.Details.PublicKey),
  778. "isCa": nc.Details.IsCA,
  779. "issuer": nc.Details.Issuer,
  780. "curve": nc.Details.Curve.String(),
  781. },
  782. "fingerprint": fp,
  783. "signature": fmt.Sprintf("%x", nc.Signature),
  784. }
  785. return json.Marshal(jc)
  786. }
  787. //func (nc *NebulaCertificate) Copy() *NebulaCertificate {
  788. // r, err := nc.Marshal()
  789. // if err != nil {
  790. // //TODO
  791. // return nil
  792. // }
  793. //
  794. // c, err := UnmarshalNebulaCertificate(r)
  795. // return c
  796. //}
  797. func (nc *NebulaCertificate) Copy() *NebulaCertificate {
  798. c := &NebulaCertificate{
  799. Details: NebulaCertificateDetails{
  800. Name: nc.Details.Name,
  801. Groups: make([]string, len(nc.Details.Groups)),
  802. Ips: make([]*net.IPNet, len(nc.Details.Ips)),
  803. Subnets: make([]*net.IPNet, len(nc.Details.Subnets)),
  804. NotBefore: nc.Details.NotBefore,
  805. NotAfter: nc.Details.NotAfter,
  806. PublicKey: make([]byte, len(nc.Details.PublicKey)),
  807. IsCA: nc.Details.IsCA,
  808. Issuer: nc.Details.Issuer,
  809. InvertedGroups: make(map[string]struct{}, len(nc.Details.InvertedGroups)),
  810. },
  811. Signature: make([]byte, len(nc.Signature)),
  812. }
  813. copy(c.Signature, nc.Signature)
  814. copy(c.Details.Groups, nc.Details.Groups)
  815. copy(c.Details.PublicKey, nc.Details.PublicKey)
  816. for i, p := range nc.Details.Ips {
  817. c.Details.Ips[i] = &net.IPNet{
  818. IP: make(net.IP, len(p.IP)),
  819. Mask: make(net.IPMask, len(p.Mask)),
  820. }
  821. copy(c.Details.Ips[i].IP, p.IP)
  822. copy(c.Details.Ips[i].Mask, p.Mask)
  823. }
  824. for i, p := range nc.Details.Subnets {
  825. c.Details.Subnets[i] = &net.IPNet{
  826. IP: make(net.IP, len(p.IP)),
  827. Mask: make(net.IPMask, len(p.Mask)),
  828. }
  829. copy(c.Details.Subnets[i].IP, p.IP)
  830. copy(c.Details.Subnets[i].Mask, p.Mask)
  831. }
  832. for g := range nc.Details.InvertedGroups {
  833. c.Details.InvertedGroups[g] = struct{}{}
  834. }
  835. return c
  836. }
  837. func netMatch(certIp *net.IPNet, rootIps []*net.IPNet) bool {
  838. for _, net := range rootIps {
  839. if net.Contains(certIp.IP) && maskContains(net.Mask, certIp.Mask) {
  840. return true
  841. }
  842. }
  843. return false
  844. }
  845. func maskContains(caMask, certMask net.IPMask) bool {
  846. caM := maskTo4(caMask)
  847. cM := maskTo4(certMask)
  848. // Make sure forcing to ipv4 didn't nuke us
  849. if caM == nil || cM == nil {
  850. return false
  851. }
  852. // Make sure the cert mask is not greater than the ca mask
  853. for i := 0; i < len(caMask); i++ {
  854. if caM[i] > cM[i] {
  855. return false
  856. }
  857. }
  858. return true
  859. }
  860. func maskTo4(ip net.IPMask) net.IPMask {
  861. if len(ip) == net.IPv4len {
  862. return ip
  863. }
  864. if len(ip) == net.IPv6len && isZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff {
  865. return ip[12:16]
  866. }
  867. return nil
  868. }
  869. func isZeros(b []byte) bool {
  870. for i := 0; i < len(b); i++ {
  871. if b[i] != 0 {
  872. return false
  873. }
  874. }
  875. return true
  876. }
  877. func ip2int(ip []byte) uint32 {
  878. if len(ip) == 16 {
  879. return binary.BigEndian.Uint32(ip[12:16])
  880. }
  881. return binary.BigEndian.Uint32(ip)
  882. }
  883. func int2ip(nn uint32) net.IP {
  884. ip := make(net.IP, net.IPv4len)
  885. binary.BigEndian.PutUint32(ip, nn)
  886. return ip
  887. }