2016-08-18 14:20:11 +02:00
package acme
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
2017-05-26 17:03:14 +02:00
"fmt"
2016-08-18 14:20:11 +02:00
"reflect"
2016-12-14 18:10:10 +01:00
"sort"
"strings"
2016-08-18 14:20:11 +02:00
"sync"
"time"
2016-12-30 09:21:13 +01:00
"github.com/containous/traefik/log"
"github.com/xenolf/lego/acme"
2016-08-18 14:20:11 +02:00
)
// Account is used to store lets encrypt registration info
type Account struct {
Email string
Registration * acme . RegistrationResource
PrivateKey [ ] byte
DomainsCertificate DomainsCertificates
2016-09-23 18:27:01 +02:00
ChallengeCerts map [ string ] * ChallengeCert
}
// ChallengeCert stores a challenge certificate
type ChallengeCert struct {
Certificate [ ] byte
PrivateKey [ ] byte
certificate * tls . Certificate
2016-08-18 14:20:11 +02:00
}
2017-06-01 22:10:19 +02:00
// Init inits account struct
2016-08-18 14:20:11 +02:00
func ( a * Account ) Init ( ) error {
err := a . DomainsCertificate . Init ( )
if err != nil {
return err
}
2016-09-23 18:27:01 +02:00
for _ , cert := range a . ChallengeCerts {
if cert . certificate == nil {
certificate , err := tls . X509KeyPair ( cert . Certificate , cert . PrivateKey )
if err != nil {
return err
}
cert . certificate = & certificate
}
if cert . certificate . Leaf == nil {
leaf , err := x509 . ParseCertificate ( cert . certificate . Certificate [ 0 ] )
if err != nil {
return err
}
cert . certificate . Leaf = leaf
}
}
2016-08-18 14:20:11 +02:00
return nil
}
2016-09-23 18:27:01 +02:00
// NewAccount creates an account
2016-08-18 14:20:11 +02:00
func NewAccount ( email string ) ( * Account , error ) {
// Create a user. New accounts need an email and private key to start
privateKey , err := rsa . GenerateKey ( rand . Reader , 4096 )
if err != nil {
return nil , err
}
domainsCerts := DomainsCertificates { Certs : [ ] * DomainsCertificate { } }
domainsCerts . Init ( )
return & Account {
Email : email ,
PrivateKey : x509 . MarshalPKCS1PrivateKey ( privateKey ) ,
2016-09-23 18:27:01 +02:00
DomainsCertificate : DomainsCertificates { Certs : domainsCerts . Certs } ,
ChallengeCerts : map [ string ] * ChallengeCert { } } , nil
2016-08-18 14:20:11 +02:00
}
// GetEmail returns email
2016-09-23 18:27:01 +02:00
func ( a * Account ) GetEmail ( ) string {
2016-08-18 14:20:11 +02:00
return a . Email
}
// GetRegistration returns lets encrypt registration resource
2016-09-23 18:27:01 +02:00
func ( a * Account ) GetRegistration ( ) * acme . RegistrationResource {
2016-08-18 14:20:11 +02:00
return a . Registration
}
// GetPrivateKey returns private key
2016-09-23 18:27:01 +02:00
func ( a * Account ) GetPrivateKey ( ) crypto . PrivateKey {
2016-08-18 14:20:11 +02:00
if privateKey , err := x509 . ParsePKCS1PrivateKey ( a . PrivateKey ) ; err == nil {
return privateKey
}
log . Errorf ( "Cannot unmarshall private key %+v" , a . PrivateKey )
return nil
}
// Certificate is used to store certificate info
type Certificate struct {
Domain string
CertURL string
CertStableURL string
PrivateKey [ ] byte
Certificate [ ] byte
}
// DomainsCertificates stores a certificate for multiple domains
type DomainsCertificates struct {
Certs [ ] * DomainsCertificate
lock sync . RWMutex
}
2016-12-14 18:10:10 +01:00
func ( dc * DomainsCertificates ) Len ( ) int {
return len ( dc . Certs )
}
func ( dc * DomainsCertificates ) Swap ( i , j int ) {
dc . Certs [ i ] , dc . Certs [ j ] = dc . Certs [ j ] , dc . Certs [ i ]
}
func ( dc * DomainsCertificates ) Less ( i , j int ) bool {
if reflect . DeepEqual ( dc . Certs [ i ] . Domains , dc . Certs [ j ] . Domains ) {
return dc . Certs [ i ] . tlsCert . Leaf . NotAfter . After ( dc . Certs [ j ] . tlsCert . Leaf . NotAfter )
}
if dc . Certs [ i ] . Domains . Main == dc . Certs [ j ] . Domains . Main {
return strings . Join ( dc . Certs [ i ] . Domains . SANs , "," ) < strings . Join ( dc . Certs [ j ] . Domains . SANs , "," )
}
return dc . Certs [ i ] . Domains . Main < dc . Certs [ j ] . Domains . Main
}
func ( dc * DomainsCertificates ) removeDuplicates ( ) {
sort . Sort ( dc )
for i := 0 ; i < len ( dc . Certs ) ; i ++ {
for i2 := i + 1 ; i2 < len ( dc . Certs ) ; i2 ++ {
if reflect . DeepEqual ( dc . Certs [ i ] . Domains , dc . Certs [ i2 ] . Domains ) {
// delete
2017-02-02 21:07:44 +01:00
log . Warnf ( "Remove duplicate cert: %+v, expiration :%s" , dc . Certs [ i2 ] . Domains , dc . Certs [ i2 ] . tlsCert . Leaf . NotAfter . String ( ) )
2016-12-14 18:10:10 +01:00
dc . Certs = append ( dc . Certs [ : i2 ] , dc . Certs [ i2 + 1 : ] ... )
i2 --
}
}
}
}
2016-09-23 18:27:01 +02:00
// Init inits DomainsCertificates
2016-08-18 14:20:11 +02:00
func ( dc * DomainsCertificates ) Init ( ) error {
dc . lock . Lock ( )
defer dc . lock . Unlock ( )
for _ , domainsCertificate := range dc . Certs {
tlsCert , err := tls . X509KeyPair ( domainsCertificate . Certificate . Certificate , domainsCertificate . Certificate . PrivateKey )
if err != nil {
return err
}
domainsCertificate . tlsCert = & tlsCert
2016-12-14 18:10:10 +01:00
if domainsCertificate . tlsCert . Leaf == nil {
leaf , err := x509 . ParseCertificate ( domainsCertificate . tlsCert . Certificate [ 0 ] )
if err != nil {
return err
}
domainsCertificate . tlsCert . Leaf = leaf
}
2016-08-18 14:20:11 +02:00
}
2016-12-14 18:10:10 +01:00
dc . removeDuplicates ( )
2016-08-18 14:20:11 +02:00
return nil
}
func ( dc * DomainsCertificates ) renewCertificates ( acmeCert * Certificate , domain Domain ) error {
dc . lock . Lock ( )
defer dc . lock . Unlock ( )
for _ , domainsCertificate := range dc . Certs {
if reflect . DeepEqual ( domain , domainsCertificate . Domains ) {
tlsCert , err := tls . X509KeyPair ( acmeCert . Certificate , acmeCert . PrivateKey )
if err != nil {
return err
}
domainsCertificate . Certificate = acmeCert
domainsCertificate . tlsCert = & tlsCert
return nil
}
}
2017-09-13 10:34:04 +02:00
return fmt . Errorf ( "certificate to renew not found for domain %s" , domain . Main )
2016-08-18 14:20:11 +02:00
}
func ( dc * DomainsCertificates ) addCertificateForDomains ( acmeCert * Certificate , domain Domain ) ( * DomainsCertificate , error ) {
dc . lock . Lock ( )
defer dc . lock . Unlock ( )
tlsCert , err := tls . X509KeyPair ( acmeCert . Certificate , acmeCert . PrivateKey )
if err != nil {
return nil , err
}
cert := DomainsCertificate { Domains : domain , Certificate : acmeCert , tlsCert : & tlsCert }
dc . Certs = append ( dc . Certs , & cert )
return & cert , nil
}
func ( dc * DomainsCertificates ) getCertificateForDomain ( domainToFind string ) ( * DomainsCertificate , bool ) {
dc . lock . RLock ( )
defer dc . lock . RUnlock ( )
for _ , domainsCertificate := range dc . Certs {
domains := [ ] string { }
domains = append ( domains , domainsCertificate . Domains . Main )
domains = append ( domains , domainsCertificate . Domains . SANs ... )
for _ , domain := range domains {
if domain == domainToFind {
return domainsCertificate , true
}
}
}
return nil , false
}
func ( dc * DomainsCertificates ) exists ( domainToFind Domain ) ( * DomainsCertificate , bool ) {
dc . lock . RLock ( )
defer dc . lock . RUnlock ( )
for _ , domainsCertificate := range dc . Certs {
if reflect . DeepEqual ( domainToFind , domainsCertificate . Domains ) {
return domainsCertificate , true
}
}
return nil , false
}
// DomainsCertificate contains a certificate for multiple domains
type DomainsCertificate struct {
Domains Domain
Certificate * Certificate
tlsCert * tls . Certificate
}
func ( dc * DomainsCertificate ) needRenew ( ) bool {
for _ , c := range dc . tlsCert . Certificate {
crt , err := x509 . ParseCertificate ( c )
if err != nil {
// If there's an error, we assume the cert is broken, and needs update
return true
}
2017-01-31 15:28:40 +01:00
// <= 30 days left, renew certificate
2016-09-23 18:27:01 +02:00
if crt . NotAfter . Before ( time . Now ( ) . Add ( time . Duration ( 24 * 30 * time . Hour ) ) ) {
2016-08-18 14:20:11 +02:00
return true
}
}
return false
}