cert_v1.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. package cert
  2. import (
  3. "bytes"
  4. "crypto/ecdh"
  5. "crypto/ecdsa"
  6. "crypto/ed25519"
  7. "crypto/elliptic"
  8. "crypto/sha256"
  9. "encoding/binary"
  10. "encoding/hex"
  11. "encoding/json"
  12. "encoding/pem"
  13. "fmt"
  14. "net"
  15. "net/netip"
  16. "time"
  17. "golang.org/x/crypto/curve25519"
  18. "google.golang.org/protobuf/proto"
  19. )
  20. const publicKeyLen = 32
  21. type certificateV1 struct {
  22. details detailsV1
  23. signature []byte
  24. }
  25. type detailsV1 struct {
  26. name string
  27. networks []netip.Prefix
  28. unsafeNetworks []netip.Prefix
  29. groups []string
  30. notBefore time.Time
  31. notAfter time.Time
  32. publicKey []byte
  33. isCA bool
  34. issuer string
  35. curve Curve
  36. }
  37. type m = map[string]any
  38. func (c *certificateV1) Version() Version {
  39. return Version1
  40. }
  41. func (c *certificateV1) Curve() Curve {
  42. return c.details.curve
  43. }
  44. func (c *certificateV1) Groups() []string {
  45. return c.details.groups
  46. }
  47. func (c *certificateV1) IsCA() bool {
  48. return c.details.isCA
  49. }
  50. func (c *certificateV1) Issuer() string {
  51. return c.details.issuer
  52. }
  53. func (c *certificateV1) Name() string {
  54. return c.details.name
  55. }
  56. func (c *certificateV1) Networks() []netip.Prefix {
  57. return c.details.networks
  58. }
  59. func (c *certificateV1) NotAfter() time.Time {
  60. return c.details.notAfter
  61. }
  62. func (c *certificateV1) NotBefore() time.Time {
  63. return c.details.notBefore
  64. }
  65. func (c *certificateV1) PublicKey() []byte {
  66. return c.details.publicKey
  67. }
  68. func (c *certificateV1) MarshalPublicKeyPEM() []byte {
  69. return marshalCertPublicKeyToPEM(c)
  70. }
  71. func (c *certificateV1) Signature() []byte {
  72. return c.signature
  73. }
  74. func (c *certificateV1) UnsafeNetworks() []netip.Prefix {
  75. return c.details.unsafeNetworks
  76. }
  77. func (c *certificateV1) Fingerprint() (string, error) {
  78. b, err := c.Marshal()
  79. if err != nil {
  80. return "", err
  81. }
  82. sum := sha256.Sum256(b)
  83. return hex.EncodeToString(sum[:]), nil
  84. }
  85. func (c *certificateV1) CheckSignature(key []byte) bool {
  86. b, err := proto.Marshal(c.getRawDetails())
  87. if err != nil {
  88. return false
  89. }
  90. switch c.details.curve {
  91. case Curve_CURVE25519:
  92. if len(key) != ed25519.PublicKeySize {
  93. return false //avoids a panic internal to ed25519
  94. }
  95. return ed25519.Verify(key, b, c.signature)
  96. case Curve_P256:
  97. pubKey, err := ecdsa.ParseUncompressedPublicKey(elliptic.P256(), key)
  98. if err != nil {
  99. return false
  100. }
  101. hashed := sha256.Sum256(b)
  102. return ecdsa.VerifyASN1(pubKey, hashed[:], c.signature)
  103. default:
  104. return false
  105. }
  106. }
  107. func (c *certificateV1) Expired(t time.Time) bool {
  108. return c.details.notBefore.After(t) || c.details.notAfter.Before(t)
  109. }
  110. func (c *certificateV1) VerifyPrivateKey(curve Curve, key []byte) error {
  111. if curve != c.details.curve {
  112. return fmt.Errorf("curve in cert and private key supplied don't match")
  113. }
  114. if c.details.isCA {
  115. switch curve {
  116. case Curve_CURVE25519:
  117. // the call to PublicKey below will panic slice bounds out of range otherwise
  118. if len(key) != ed25519.PrivateKeySize {
  119. return fmt.Errorf("key was not 64 bytes, is invalid ed25519 private key")
  120. }
  121. if !ed25519.PublicKey(c.details.publicKey).Equal(ed25519.PrivateKey(key).Public()) {
  122. return fmt.Errorf("public key in cert and private key supplied don't match")
  123. }
  124. case Curve_P256:
  125. privkey, err := ecdh.P256().NewPrivateKey(key)
  126. if err != nil {
  127. return fmt.Errorf("cannot parse private key as P256: %w", err)
  128. }
  129. pub := privkey.PublicKey().Bytes()
  130. if !bytes.Equal(pub, c.details.publicKey) {
  131. return fmt.Errorf("public key in cert and private key supplied don't match")
  132. }
  133. default:
  134. return fmt.Errorf("invalid curve: %s", curve)
  135. }
  136. return nil
  137. }
  138. var pub []byte
  139. switch curve {
  140. case Curve_CURVE25519:
  141. var err error
  142. pub, err = curve25519.X25519(key, curve25519.Basepoint)
  143. if err != nil {
  144. return err
  145. }
  146. case Curve_P256:
  147. privkey, err := ecdh.P256().NewPrivateKey(key)
  148. if err != nil {
  149. return err
  150. }
  151. pub = privkey.PublicKey().Bytes()
  152. default:
  153. return fmt.Errorf("invalid curve: %s", curve)
  154. }
  155. if !bytes.Equal(pub, c.details.publicKey) {
  156. return fmt.Errorf("public key in cert and private key supplied don't match")
  157. }
  158. return nil
  159. }
  160. // getRawDetails marshals the raw details into protobuf ready struct
  161. func (c *certificateV1) getRawDetails() *RawNebulaCertificateDetails {
  162. rd := &RawNebulaCertificateDetails{
  163. Name: c.details.name,
  164. Groups: c.details.groups,
  165. NotBefore: c.details.notBefore.Unix(),
  166. NotAfter: c.details.notAfter.Unix(),
  167. PublicKey: make([]byte, len(c.details.publicKey)),
  168. IsCA: c.details.isCA,
  169. Curve: c.details.curve,
  170. }
  171. for _, ipNet := range c.details.networks {
  172. mask := net.CIDRMask(ipNet.Bits(), ipNet.Addr().BitLen())
  173. rd.Ips = append(rd.Ips, addr2int(ipNet.Addr()), ip2int(mask))
  174. }
  175. for _, ipNet := range c.details.unsafeNetworks {
  176. mask := net.CIDRMask(ipNet.Bits(), ipNet.Addr().BitLen())
  177. rd.Subnets = append(rd.Subnets, addr2int(ipNet.Addr()), ip2int(mask))
  178. }
  179. copy(rd.PublicKey, c.details.publicKey[:])
  180. // I know, this is terrible
  181. rd.Issuer, _ = hex.DecodeString(c.details.issuer)
  182. return rd
  183. }
  184. func (c *certificateV1) String() string {
  185. b, err := json.MarshalIndent(c.marshalJSON(), "", "\t")
  186. if err != nil {
  187. return fmt.Sprintf("<error marshalling certificate: %v>", err)
  188. }
  189. return string(b)
  190. }
  191. func (c *certificateV1) MarshalForHandshakes() ([]byte, error) {
  192. pubKey := c.details.publicKey
  193. c.details.publicKey = nil
  194. rawCertNoKey, err := c.Marshal()
  195. if err != nil {
  196. return nil, err
  197. }
  198. c.details.publicKey = pubKey
  199. return rawCertNoKey, nil
  200. }
  201. func (c *certificateV1) Marshal() ([]byte, error) {
  202. rc := RawNebulaCertificate{
  203. Details: c.getRawDetails(),
  204. Signature: c.signature,
  205. }
  206. return proto.Marshal(&rc)
  207. }
  208. func (c *certificateV1) MarshalPEM() ([]byte, error) {
  209. b, err := c.Marshal()
  210. if err != nil {
  211. return nil, err
  212. }
  213. return pem.EncodeToMemory(&pem.Block{Type: CertificateBanner, Bytes: b}), nil
  214. }
  215. func (c *certificateV1) MarshalJSON() ([]byte, error) {
  216. return json.Marshal(c.marshalJSON())
  217. }
  218. func (c *certificateV1) marshalJSON() m {
  219. fp, _ := c.Fingerprint()
  220. return m{
  221. "version": Version1,
  222. "details": m{
  223. "name": c.details.name,
  224. "networks": c.details.networks,
  225. "unsafeNetworks": c.details.unsafeNetworks,
  226. "groups": c.details.groups,
  227. "notBefore": c.details.notBefore,
  228. "notAfter": c.details.notAfter,
  229. "publicKey": fmt.Sprintf("%x", c.details.publicKey),
  230. "isCa": c.details.isCA,
  231. "issuer": c.details.issuer,
  232. "curve": c.details.curve.String(),
  233. },
  234. "fingerprint": fp,
  235. "signature": fmt.Sprintf("%x", c.Signature()),
  236. }
  237. }
  238. func (c *certificateV1) Copy() Certificate {
  239. nc := &certificateV1{
  240. details: detailsV1{
  241. name: c.details.name,
  242. notBefore: c.details.notBefore,
  243. notAfter: c.details.notAfter,
  244. publicKey: make([]byte, len(c.details.publicKey)),
  245. isCA: c.details.isCA,
  246. issuer: c.details.issuer,
  247. curve: c.details.curve,
  248. },
  249. signature: make([]byte, len(c.signature)),
  250. }
  251. if c.details.groups != nil {
  252. nc.details.groups = make([]string, len(c.details.groups))
  253. copy(nc.details.groups, c.details.groups)
  254. }
  255. if c.details.networks != nil {
  256. nc.details.networks = make([]netip.Prefix, len(c.details.networks))
  257. copy(nc.details.networks, c.details.networks)
  258. }
  259. if c.details.unsafeNetworks != nil {
  260. nc.details.unsafeNetworks = make([]netip.Prefix, len(c.details.unsafeNetworks))
  261. copy(nc.details.unsafeNetworks, c.details.unsafeNetworks)
  262. }
  263. copy(nc.signature, c.signature)
  264. copy(nc.details.publicKey, c.details.publicKey)
  265. return nc
  266. }
  267. func (c *certificateV1) fromTBSCertificate(t *TBSCertificate) error {
  268. c.details = detailsV1{
  269. name: t.Name,
  270. networks: t.Networks,
  271. unsafeNetworks: t.UnsafeNetworks,
  272. groups: t.Groups,
  273. notBefore: t.NotBefore,
  274. notAfter: t.NotAfter,
  275. publicKey: t.PublicKey,
  276. isCA: t.IsCA,
  277. curve: t.Curve,
  278. issuer: t.issuer,
  279. }
  280. return c.validate()
  281. }
  282. func (c *certificateV1) validate() error {
  283. // Empty names are allowed
  284. if len(c.details.publicKey) == 0 {
  285. return ErrInvalidPublicKey
  286. }
  287. // Original v1 rules allowed multiple networks to be present but ignored all but the first one.
  288. // Continue to allow this behavior
  289. if !c.details.isCA && len(c.details.networks) == 0 {
  290. return NewErrInvalidCertificateProperties("non-CA certificates must contain exactly one network")
  291. }
  292. for _, network := range c.details.networks {
  293. if !network.IsValid() || !network.Addr().IsValid() {
  294. return NewErrInvalidCertificateProperties("invalid network: %s", network)
  295. }
  296. if network.Addr().Is6() {
  297. return NewErrInvalidCertificateProperties("certificate may not contain IPv6 networks: %v", network)
  298. }
  299. if network.Addr().IsUnspecified() {
  300. return NewErrInvalidCertificateProperties("non-CA certificates must not use the zero address as a network: %s", network)
  301. }
  302. if network.Addr().Zone() != "" {
  303. return NewErrInvalidCertificateProperties("networks may not contain zones: %s", network)
  304. }
  305. }
  306. for _, network := range c.details.unsafeNetworks {
  307. if !network.IsValid() || !network.Addr().IsValid() {
  308. return NewErrInvalidCertificateProperties("invalid unsafe network: %s", network)
  309. }
  310. if network.Addr().Is6() {
  311. return NewErrInvalidCertificateProperties("certificate may not contain IPv6 unsafe networks: %v", network)
  312. }
  313. if network.Addr().Zone() != "" {
  314. return NewErrInvalidCertificateProperties("unsafe networks may not contain zones: %s", network)
  315. }
  316. }
  317. // v1 doesn't bother with sort order or uniqueness of networks or unsafe networks.
  318. // We can't modify the unmarshalled data because verification requires re-marshalling and a re-ordered
  319. // unsafe networks would result in a different signature.
  320. return nil
  321. }
  322. func (c *certificateV1) marshalForSigning() ([]byte, error) {
  323. b, err := proto.Marshal(c.getRawDetails())
  324. if err != nil {
  325. return nil, err
  326. }
  327. return b, nil
  328. }
  329. func (c *certificateV1) setSignature(b []byte) error {
  330. if len(b) == 0 {
  331. return ErrEmptySignature
  332. }
  333. c.signature = b
  334. return nil
  335. }
  336. // unmarshalCertificateV1 will unmarshal a protobuf byte representation of a nebula cert
  337. // if the publicKey is provided here then it is not required to be present in `b`
  338. func unmarshalCertificateV1(b []byte, publicKey []byte) (*certificateV1, error) {
  339. if len(b) == 0 {
  340. return nil, fmt.Errorf("nil byte array")
  341. }
  342. var rc RawNebulaCertificate
  343. err := proto.Unmarshal(b, &rc)
  344. if err != nil {
  345. return nil, err
  346. }
  347. if rc.Details == nil {
  348. return nil, fmt.Errorf("encoded Details was nil")
  349. }
  350. if len(rc.Details.Ips)%2 != 0 {
  351. return nil, fmt.Errorf("encoded IPs should be in pairs, an odd number was found")
  352. }
  353. if len(rc.Details.Subnets)%2 != 0 {
  354. return nil, fmt.Errorf("encoded Subnets should be in pairs, an odd number was found")
  355. }
  356. nc := certificateV1{
  357. details: detailsV1{
  358. name: rc.Details.Name,
  359. groups: make([]string, len(rc.Details.Groups)),
  360. networks: make([]netip.Prefix, len(rc.Details.Ips)/2),
  361. unsafeNetworks: make([]netip.Prefix, len(rc.Details.Subnets)/2),
  362. notBefore: time.Unix(rc.Details.NotBefore, 0),
  363. notAfter: time.Unix(rc.Details.NotAfter, 0),
  364. publicKey: nil,
  365. isCA: rc.Details.IsCA,
  366. curve: rc.Details.Curve,
  367. },
  368. signature: make([]byte, len(rc.Signature)),
  369. }
  370. copy(nc.signature, rc.Signature)
  371. copy(nc.details.groups, rc.Details.Groups)
  372. nc.details.issuer = hex.EncodeToString(rc.Details.Issuer)
  373. // If a public key is passed in as an argument, the certificate pubkey must be empty
  374. // and the passed-in pubkey copied into the cert.
  375. if len(publicKey) > 0 {
  376. if len(rc.Details.PublicKey) != 0 {
  377. return nil, ErrCertPubkeyPresent
  378. }
  379. nc.details.publicKey = make([]byte, len(publicKey))
  380. copy(nc.details.publicKey, publicKey)
  381. } else {
  382. nc.details.publicKey = make([]byte, len(rc.Details.PublicKey))
  383. copy(nc.details.publicKey, rc.Details.PublicKey)
  384. }
  385. var ip netip.Addr
  386. for i, rawIp := range rc.Details.Ips {
  387. if i%2 == 0 {
  388. ip = int2addr(rawIp)
  389. } else {
  390. ones, _ := net.IPMask(int2ip(rawIp)).Size()
  391. nc.details.networks[i/2] = netip.PrefixFrom(ip, ones)
  392. }
  393. }
  394. for i, rawIp := range rc.Details.Subnets {
  395. if i%2 == 0 {
  396. ip = int2addr(rawIp)
  397. } else {
  398. ones, _ := net.IPMask(int2ip(rawIp)).Size()
  399. nc.details.unsafeNetworks[i/2] = netip.PrefixFrom(ip, ones)
  400. }
  401. }
  402. err = nc.validate()
  403. if err != nil {
  404. return nil, err
  405. }
  406. return &nc, nil
  407. }
  408. func ip2int(ip []byte) uint32 {
  409. if len(ip) == 16 {
  410. return binary.BigEndian.Uint32(ip[12:16])
  411. }
  412. return binary.BigEndian.Uint32(ip)
  413. }
  414. func int2ip(nn uint32) net.IP {
  415. ip := make(net.IP, net.IPv4len)
  416. binary.BigEndian.PutUint32(ip, nn)
  417. return ip
  418. }
  419. func addr2int(addr netip.Addr) uint32 {
  420. b := addr.Unmap().As4()
  421. return binary.BigEndian.Uint32(b[:])
  422. }
  423. func int2addr(nn uint32) netip.Addr {
  424. ip := [4]byte{}
  425. binary.BigEndian.PutUint32(ip[:], nn)
  426. return netip.AddrFrom4(ip).Unmap()
  427. }