certutil.go 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package certutil
  2. import (
  3. "crypto/x509"
  4. "encoding/json"
  5. "encoding/pem"
  6. "fmt"
  7. "strings"
  8. )
  9. type namedTunnelToken struct {
  10. ZoneID string `json:"zoneID"`
  11. AccountID string `json:"accountID"`
  12. ServiceKey string `json:"serviceKey"`
  13. }
  14. type OriginCert struct {
  15. PrivateKey interface{}
  16. Cert *x509.Certificate
  17. ZoneID string
  18. ServiceKey string
  19. AccountID string
  20. }
  21. func DecodeOriginCert(blocks []byte) (*OriginCert, error) {
  22. if len(blocks) == 0 {
  23. return nil, fmt.Errorf("Cannot decode empty certificate")
  24. }
  25. originCert := OriginCert{}
  26. block, rest := pem.Decode(blocks)
  27. for {
  28. if block == nil {
  29. break
  30. }
  31. switch block.Type {
  32. case "PRIVATE KEY":
  33. if originCert.PrivateKey != nil {
  34. return nil, fmt.Errorf("Found multiple private key in the certificate")
  35. }
  36. // RSA private key
  37. privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
  38. if err != nil {
  39. return nil, fmt.Errorf("Cannot parse private key")
  40. }
  41. originCert.PrivateKey = privateKey
  42. case "CERTIFICATE":
  43. if originCert.Cert != nil {
  44. return nil, fmt.Errorf("Found multiple certificates in the certificate")
  45. }
  46. cert, err := x509.ParseCertificates(block.Bytes)
  47. if err != nil {
  48. return nil, fmt.Errorf("Cannot parse certificate")
  49. } else if len(cert) > 1 {
  50. return nil, fmt.Errorf("Found multiple certificates in the certificate")
  51. }
  52. originCert.Cert = cert[0]
  53. case "WARP TOKEN", "ARGO TUNNEL TOKEN":
  54. if originCert.ZoneID != "" || originCert.ServiceKey != "" {
  55. return nil, fmt.Errorf("Found multiple tokens in the certificate")
  56. }
  57. // The token is a string,
  58. // Try the newer JSON format
  59. ntt := namedTunnelToken{}
  60. if err := json.Unmarshal(block.Bytes, &ntt); err == nil {
  61. originCert.ZoneID = ntt.ZoneID
  62. originCert.ServiceKey = ntt.ServiceKey
  63. originCert.AccountID = ntt.AccountID
  64. } else {
  65. // Try the older format, where the zoneID and service key are seperated by
  66. // a new line character
  67. token := string(block.Bytes)
  68. s := strings.Split(token, "\n")
  69. if len(s) != 2 {
  70. return nil, fmt.Errorf("Cannot parse token")
  71. }
  72. originCert.ZoneID = s[0]
  73. originCert.ServiceKey = s[1]
  74. }
  75. default:
  76. return nil, fmt.Errorf("Unknown block %s in the certificate", block.Type)
  77. }
  78. block, rest = pem.Decode(rest)
  79. }
  80. if originCert.PrivateKey == nil {
  81. return nil, fmt.Errorf("Missing private key in the certificate")
  82. } else if originCert.Cert == nil {
  83. return nil, fmt.Errorf("Missing certificate in the certificate")
  84. } else if originCert.ZoneID == "" || originCert.ServiceKey == "" {
  85. return nil, fmt.Errorf("Missing token in the certificate")
  86. }
  87. return &originCert, nil
  88. }