2323package service
2424
2525import (
26- "crypto"
27- "crypto/ecdsa"
28- "crypto/rand"
29- "crypto/rsa"
3026 "crypto/tls"
31- "crypto/x509"
3227 "crypto/x509/pkix"
33- "encoding/pem"
34- "errors"
35- "fmt"
3628 "io/ioutil"
37- "math/big"
38- "net"
3929 "strings"
4030 "time"
31+
32+ certificates "github.com/arangodb-helper/go-certificates"
4133)
4234
4335// CreateCertificateOptions configures how to create a certificate.
4436type CreateCertificateOptions struct {
4537 Hosts []string // Host names and/or IP addresses
4638 ValidFor time.Duration
47- RSABits int
4839 Organization string
4940}
5041
5142const (
5243 defaultValidFor = time .Hour * 24 * 365 // 1year
44+ defaultCurve = "P256"
5345)
5446
55- func publicKey (priv interface {}) interface {} {
56- switch k := priv .(type ) {
57- case * rsa.PrivateKey :
58- return & k .PublicKey
59- default :
60- return nil
61- }
62- }
63-
64- func pemBlockForKey (priv interface {}) * pem.Block {
65- switch k := priv .(type ) {
66- case * rsa.PrivateKey :
67- return & pem.Block {Type : "RSA PRIVATE KEY" , Bytes : x509 .MarshalPKCS1PrivateKey (k )}
68- default :
69- return nil
70- }
71- }
72-
73- // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
74- // PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
75- // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
76- func parsePrivateKey (der []byte ) (crypto.PrivateKey , error ) {
77- if key , err := x509 .ParsePKCS1PrivateKey (der ); err == nil {
78- return key , nil
79- }
80- if key , err := x509 .ParsePKCS8PrivateKey (der ); err == nil {
81- switch key := key .(type ) {
82- case * rsa.PrivateKey , * ecdsa.PrivateKey :
83- return key , nil
84- default :
85- return nil , maskAny (errors .New ("tls: found unknown private key type in PKCS#8 wrapping" ))
86- }
87- }
88- if key , err := x509 .ParseECPrivateKey (der ); err == nil {
89- return key , nil
90- }
91-
92- return nil , maskAny (errors .New ("tls: failed to parse private key" ))
93- }
94-
9547// CreateCertificate creates a self-signed certificate according to the given configuration.
9648// The resulting certificate + private key will be written into a single file in the given folder.
9749// The path of that single file is returned.
9850func CreateCertificate (options CreateCertificateOptions , folder string ) (string , error ) {
99- priv , err := rsa .GenerateKey (rand .Reader , options .RSABits )
100- if err != nil {
101- return "" , maskAny (err )
102- }
103-
104- notBefore := time .Now ()
10551 if options .ValidFor == 0 {
10652 options .ValidFor = defaultValidFor
10753 }
108- notAfter := notBefore .Add (options .ValidFor )
109-
110- serialNumberLimit := new (big.Int ).Lsh (big .NewInt (1 ), 128 )
111- serialNumber , err := rand .Int (rand .Reader , serialNumberLimit )
112- if err != nil {
113- return "" , maskAny (fmt .Errorf ("failed to generate serial number: %v" , err ))
114- }
115-
116- template := x509.Certificate {
117- SerialNumber : serialNumber ,
118- Subject : pkix.Name {
54+ certOpts := certificates.CreateCertificateOptions {
55+ Hosts : options .Hosts ,
56+ Subject : & pkix.Name {
11957 Organization : []string {options .Organization },
12058 },
121- NotBefore : notBefore ,
122- NotAfter : notAfter ,
123-
124- KeyUsage : x509 .KeyUsageKeyEncipherment | x509 .KeyUsageDigitalSignature ,
125- ExtKeyUsage : []x509.ExtKeyUsage {x509 .ExtKeyUsageServerAuth },
126- BasicConstraintsValid : true ,
127- }
128-
129- for _ , h := range options .Hosts {
130- if ip := net .ParseIP (h ); ip != nil {
131- template .IPAddresses = append (template .IPAddresses , ip )
132- } else {
133- template .DNSNames = append (template .DNSNames , h )
134- }
59+ ValidFrom : time .Now (),
60+ ValidFor : options .ValidFor ,
61+ ECDSACurve : defaultCurve ,
13562 }
13663
137- // Create the certificate
138- derBytes , err := x509 .CreateCertificate (rand . Reader , & template , & template , publicKey ( priv ), priv )
64+ // Create self-signed certificate
65+ cert , priv , err := certificates .CreateCertificate (certOpts , nil )
13966 if err != nil {
140- return "" , maskAny (fmt . Errorf ( "Failed to create certificate: %v" , err ) )
67+ return "" , maskAny (err )
14168 }
14269
14370 // Write the certificate to disk
@@ -146,46 +73,19 @@ func CreateCertificate(options CreateCertificateOptions, folder string) (string,
14673 return "" , maskAny (err )
14774 }
14875 defer f .Close ()
149- // Public key
150- pem . Encode ( f , & pem. Block { Type : "CERTIFICATE" , Bytes : derBytes })
151- // Private key
152- pem . Encode ( f , pemBlockForKey ( priv ))
76+ content := strings . TrimSpace ( cert ) + " \n " + priv
77+ if _ , err := f . WriteString ( content ); err != nil {
78+ return "" , maskAny ( err )
79+ }
15380
15481 return f .Name (), nil
15582}
15683
15784// LoadKeyFile loads a SSL keyfile formatted for the arangod server.
15885func LoadKeyFile (keyFile string ) (tls.Certificate , error ) {
159- raw , err := ioutil . ReadFile (keyFile )
86+ result , err := certificates . LoadKeyFile (keyFile )
16087 if err != nil {
16188 return tls.Certificate {}, maskAny (err )
16289 }
163-
164- result := tls.Certificate {}
165- for {
166- var derBlock * pem.Block
167- derBlock , raw = pem .Decode (raw )
168- if derBlock == nil {
169- break
170- }
171- if derBlock .Type == "CERTIFICATE" {
172- result .Certificate = append (result .Certificate , derBlock .Bytes )
173- } else if derBlock .Type == "PRIVATE KEY" || strings .HasSuffix (derBlock .Type , " PRIVATE KEY" ) {
174- if result .PrivateKey == nil {
175- result .PrivateKey , err = parsePrivateKey (derBlock .Bytes )
176- if err != nil {
177- return tls.Certificate {}, maskAny (err )
178- }
179- }
180- }
181- }
182-
183- if len (result .Certificate ) == 0 {
184- return tls.Certificate {}, maskAny (fmt .Errorf ("No certificates found in %s" , keyFile ))
185- }
186- if result .PrivateKey == nil {
187- return tls.Certificate {}, maskAny (fmt .Errorf ("No private key found in %s" , keyFile ))
188- }
189-
19090 return result , nil
19191}
0 commit comments