vendor/github.com/planetscale/planetscale-go/planetscale/certs.go in planetscale-0.2.1 vs vendor/github.com/planetscale/planetscale-go/planetscale/certs.go in planetscale-0.3.0
- old
+ new
@@ -1,37 +1,38 @@
package planetscale
import (
"bytes"
"context"
+ "crypto"
+ "crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
- "errors"
"fmt"
"net/http"
)
type CreateCertificateRequest struct {
Organization string
DatabaseName string
Branch string
- // PrivateKey is used to sign the Certificate Sign Request (CSR).
- PrivateKey *rsa.PrivateKey
+ // PrivateKey is used to generate the Certificate Sign Request (CSR).
+ PrivateKey crypto.PrivateKey
}
type CertificatesService interface {
Create(context.Context, *CreateCertificateRequest) (*Cert, error)
}
type Cert struct {
ClientCert tls.Certificate
- CACert *x509.Certificate
+ CACerts []*x509.Certificate
RemoteAddr string
Ports RemotePorts
}
type RemotePorts struct {
@@ -55,14 +56,20 @@
cn := fmt.Sprintf("%s/%s/%s", r.Organization, r.DatabaseName, r.Branch)
subj := pkix.Name{
CommonName: cn,
}
+ switch priv := r.PrivateKey.(type) {
+ case *rsa.PrivateKey:
+ case *ecdsa.PrivateKey:
+ default:
+ return nil, fmt.Errorf("unsupported key type: %T, only supports ECDSA and RSA private keys", priv)
+ }
+
template := x509.CertificateRequest{
- Version: 1,
- Subject: subj,
- SignatureAlgorithm: x509.SHA256WithRSA,
+ Version: 1,
+ Subject: subj,
}
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, r.PrivateKey)
if err != nil {
return nil, fmt.Errorf("unable to create csr: %s", err)
@@ -103,40 +110,57 @@
err = c.client.do(ctx, req, &cr)
if err != nil {
return nil, err
}
- caCert, err := parseCert(cr.CertificateChain)
+ caCerts, err := parseCerts(cr.CertificateChain)
if err != nil {
return nil, fmt.Errorf("parsing certificate chain failed: %s", err)
}
+ privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(r.PrivateKey)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal private key: %s", err)
+ }
+
privateKey := pem.EncodeToMemory(
&pem.Block{
- Type: "RSA PRIVATE KEY",
- Bytes: x509.MarshalPKCS1PrivateKey(r.PrivateKey),
+ Type: "PRIVATE KEY",
+ Bytes: privateKeyBytes,
},
)
clientCert, err := tls.X509KeyPair([]byte(cr.Certificate), privateKey)
if err != nil {
return nil, fmt.Errorf("parsing client certificate failed: %s", err)
}
return &Cert{
ClientCert: clientCert,
- CACert: caCert,
+ CACerts: caCerts,
RemoteAddr: cr.RemoteAddr,
Ports: RemotePorts{
Proxy: cr.Ports["proxy"],
MySQL: cr.Ports["mysql-tls"],
},
}, nil
}
-func parseCert(pemCert string) (*x509.Certificate, error) {
- bl, _ := pem.Decode([]byte(pemCert))
- if bl == nil {
- return nil, errors.New("invalid PEM: " + pemCert)
+func parseCerts(pemCert string) ([]*x509.Certificate, error) {
+ perCertBlock := []byte(pemCert)
+ var certs []*x509.Certificate
+
+ for {
+ var certBlock *pem.Block
+ certBlock, perCertBlock = pem.Decode(perCertBlock)
+ if certBlock == nil {
+ break
+ }
+ cert, err := x509.ParseCertificate(certBlock.Bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ certs = append(certs, cert)
}
- return x509.ParseCertificate(bl.Bytes)
+ return certs, nil
}