95 lines
2.6 KiB
Go
95 lines
2.6 KiB
Go
package certutil
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"encoding/json"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type namedTunnelToken struct {
|
|
ZoneID string `json:"zoneID"`
|
|
AccountID string `json:"accountID"`
|
|
ServiceKey string `json:"serviceKey"`
|
|
}
|
|
|
|
type OriginCert struct {
|
|
PrivateKey interface{}
|
|
Cert *x509.Certificate
|
|
ZoneID string
|
|
ServiceKey string
|
|
AccountID string
|
|
}
|
|
|
|
func DecodeOriginCert(blocks []byte) (*OriginCert, error) {
|
|
if len(blocks) == 0 {
|
|
return nil, fmt.Errorf("Cannot decode empty certificate")
|
|
}
|
|
originCert := OriginCert{}
|
|
block, rest := pem.Decode(blocks)
|
|
for {
|
|
if block == nil {
|
|
break
|
|
}
|
|
switch block.Type {
|
|
case "PRIVATE KEY":
|
|
if originCert.PrivateKey != nil {
|
|
return nil, fmt.Errorf("Found multiple private key in the certificate")
|
|
}
|
|
// RSA private key
|
|
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Cannot parse private key")
|
|
}
|
|
originCert.PrivateKey = privateKey
|
|
case "CERTIFICATE":
|
|
if originCert.Cert != nil {
|
|
return nil, fmt.Errorf("Found multiple certificates in the certificate")
|
|
}
|
|
cert, err := x509.ParseCertificates(block.Bytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Cannot parse certificate")
|
|
} else if len(cert) > 1 {
|
|
return nil, fmt.Errorf("Found multiple certificates in the certificate")
|
|
}
|
|
originCert.Cert = cert[0]
|
|
case "WARP TOKEN", "ARGO TUNNEL TOKEN":
|
|
if originCert.ZoneID != "" || originCert.ServiceKey != "" {
|
|
return nil, fmt.Errorf("Found multiple tokens in the certificate")
|
|
}
|
|
// The token is a string,
|
|
// Try the newer JSON format
|
|
ntt := namedTunnelToken{}
|
|
if err := json.Unmarshal(block.Bytes, &ntt); err == nil {
|
|
originCert.ZoneID = ntt.ZoneID
|
|
originCert.ServiceKey = ntt.ServiceKey
|
|
originCert.AccountID = ntt.AccountID
|
|
} else {
|
|
// Try the older format, where the zoneID and service key are separated by
|
|
// a new line character
|
|
token := string(block.Bytes)
|
|
s := strings.Split(token, "\n")
|
|
if len(s) != 2 {
|
|
return nil, fmt.Errorf("Cannot parse token")
|
|
}
|
|
originCert.ZoneID = s[0]
|
|
originCert.ServiceKey = s[1]
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("Unknown block %s in the certificate", block.Type)
|
|
}
|
|
block, rest = pem.Decode(rest)
|
|
}
|
|
|
|
if originCert.PrivateKey == nil {
|
|
return nil, fmt.Errorf("Missing private key in the certificate")
|
|
} else if originCert.Cert == nil {
|
|
return nil, fmt.Errorf("Missing certificate in the certificate")
|
|
} else if originCert.ZoneID == "" || originCert.ServiceKey == "" {
|
|
return nil, fmt.Errorf("Missing token in the certificate")
|
|
}
|
|
|
|
return &originCert, nil
|
|
}
|