2017-11-09 12:16:03 +01:00
package generate
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/hex"
"encoding/pem"
"fmt"
"math/big"
"time"
)
2020-05-11 12:06:07 +02:00
// DefaultDomain Traefik domain for the default certificate.
2018-07-03 12:44:04 +02:00
const DefaultDomain = "TRAEFIK DEFAULT CERT"
2020-05-11 12:06:07 +02:00
// DefaultCertificate generates random TLS certificates.
2017-11-09 12:16:03 +01:00
func DefaultCertificate ( ) ( * tls . Certificate , error ) {
randomBytes := make ( [ ] byte , 100 )
_ , err := rand . Read ( randomBytes )
if err != nil {
return nil , err
}
zBytes := sha256 . Sum256 ( randomBytes )
z := hex . EncodeToString ( zBytes [ : sha256 . Size ] )
domain := fmt . Sprintf ( "%s.%s.traefik.default" , z [ : 32 ] , z [ 32 : ] )
certPEM , keyPEM , err := KeyPair ( domain , time . Time { } )
if err != nil {
return nil , err
}
certificate , err := tls . X509KeyPair ( certPEM , keyPEM )
if err != nil {
return nil , err
}
return & certificate , nil
}
2020-05-11 12:06:07 +02:00
// KeyPair generates cert and key files.
2017-11-09 12:16:03 +01:00
func KeyPair ( domain string , expiration time . Time ) ( [ ] byte , [ ] byte , error ) {
rsaPrivKey , err := rsa . GenerateKey ( rand . Reader , 2048 )
if err != nil {
return nil , nil , err
}
keyPEM := pem . EncodeToMemory ( & pem . Block { Type : "RSA PRIVATE KEY" , Bytes : x509 . MarshalPKCS1PrivateKey ( rsaPrivKey ) } )
certPEM , err := PemCert ( rsaPrivKey , domain , expiration )
if err != nil {
return nil , nil , err
}
return certPEM , keyPEM , nil
}
2020-05-11 12:06:07 +02:00
// PemCert generates PEM cert file.
2017-11-09 12:16:03 +01:00
func PemCert ( privKey * rsa . PrivateKey , domain string , expiration time . Time ) ( [ ] byte , error ) {
derBytes , err := derCert ( privKey , expiration , domain )
if err != nil {
return nil , err
}
return pem . EncodeToMemory ( & pem . Block { Type : "CERTIFICATE" , Bytes : derBytes } ) , nil
}
func derCert ( privKey * rsa . PrivateKey , expiration time . Time , domain string ) ( [ ] byte , error ) {
serialNumberLimit := new ( big . Int ) . Lsh ( big . NewInt ( 1 ) , 128 )
serialNumber , err := rand . Int ( rand . Reader , serialNumberLimit )
if err != nil {
return nil , err
}
if expiration . IsZero ( ) {
2018-04-11 10:36:03 +02:00
expiration = time . Now ( ) . Add ( 365 * ( 24 * time . Hour ) )
2017-11-09 12:16:03 +01:00
}
template := x509 . Certificate {
SerialNumber : serialNumber ,
Subject : pkix . Name {
2018-07-03 12:44:04 +02:00
CommonName : DefaultDomain ,
2017-11-09 12:16:03 +01:00
} ,
NotBefore : time . Now ( ) ,
NotAfter : expiration ,
2019-08-05 07:20:05 -06:00
KeyUsage : x509 . KeyUsageKeyEncipherment | x509 . KeyUsageDigitalSignature | x509 . KeyUsageKeyAgreement | x509 . KeyUsageDataEncipherment ,
2019-10-25 10:08:05 -05:00
ExtKeyUsage : [ ] x509 . ExtKeyUsage { x509 . ExtKeyUsageServerAuth } ,
2017-11-09 12:16:03 +01:00
BasicConstraintsValid : true ,
DNSNames : [ ] string { domain } ,
}
return x509 . CreateCertificate ( rand . Reader , & template , & template , & privKey . PublicKey , privKey )
}