cert.go 30 KB

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