2018-01-21 13:18:26 +00:00
|
|
|
package pki
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"crypto/rand"
|
|
|
|
"crypto/x509"
|
|
|
|
"crypto/x509/pkix"
|
|
|
|
"encoding/pem"
|
|
|
|
"errors"
|
|
|
|
"io/ioutil"
|
|
|
|
"math/big"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
var passwordCA string
|
|
|
|
|
|
|
|
func SetCAPassword(pass string) {
|
|
|
|
passwordCA = pass
|
|
|
|
}
|
|
|
|
|
|
|
|
func CACertPath() string {
|
|
|
|
return path.Join(PKIDir, "shared", "ca.pem")
|
|
|
|
}
|
|
|
|
|
|
|
|
func CAPrivkeyPath() string {
|
|
|
|
return path.Join(PKIDir, "ca.key")
|
|
|
|
}
|
|
|
|
|
|
|
|
func GenerateCA(notBefore time.Time, notAfter time.Time) error {
|
|
|
|
ca := &x509.Certificate{
|
|
|
|
SerialNumber: big.NewInt(0),
|
|
|
|
Subject: pkix.Name{
|
|
|
|
Organization: []string{"EPITA"},
|
|
|
|
OrganizationalUnit: []string{"SRS laboratory"},
|
|
|
|
Country: []string{"FR"},
|
|
|
|
Locality: []string{"Paris"},
|
|
|
|
CommonName: "FIC CA",
|
|
|
|
},
|
|
|
|
NotBefore: notBefore,
|
|
|
|
NotAfter: notAfter,
|
|
|
|
IsCA: true,
|
|
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
|
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
|
|
BasicConstraintsValid: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure directories exists
|
2023-07-14 14:49:57 +00:00
|
|
|
os.Mkdir(PKIDir, 0751)
|
|
|
|
os.Mkdir(path.Join(PKIDir, "shared"), 0751)
|
2018-01-21 13:18:26 +00:00
|
|
|
|
|
|
|
pub, priv, err := GeneratePrivKey()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, pub, priv)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save certificate to file
|
|
|
|
if err := saveCertificate(CACertPath(), ca_b); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save private key to file
|
|
|
|
if err := savePrivateKeyEncrypted(CAPrivkeyPath(), priv, passwordCA); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func LoadCA() (priv ecdsa.PrivateKey, ca x509.Certificate, err error) {
|
|
|
|
// Load certificate
|
2020-01-18 22:45:28 +00:00
|
|
|
if fd, errr := os.Open(CACertPath()); errr != nil {
|
2018-01-21 13:18:26 +00:00
|
|
|
return priv, ca, errr
|
|
|
|
} else {
|
|
|
|
defer fd.Close()
|
2020-01-18 22:45:28 +00:00
|
|
|
if cert, errr := ioutil.ReadAll(fd); errr != nil {
|
2018-01-21 13:18:26 +00:00
|
|
|
return priv, ca, errr
|
|
|
|
} else {
|
|
|
|
block, _ := pem.Decode(cert)
|
|
|
|
if block == nil || block.Type != "CERTIFICATE" {
|
|
|
|
return priv, ca, errors.New("failed to decode PEM block containing certificate")
|
|
|
|
}
|
2020-01-18 22:45:28 +00:00
|
|
|
if catmp, errr := x509.ParseCertificate(block.Bytes); errr != nil {
|
2018-01-21 13:18:26 +00:00
|
|
|
return priv, ca, errr
|
|
|
|
} else if catmp == nil {
|
|
|
|
return priv, ca, errors.New("failed to parse certificate")
|
|
|
|
} else {
|
|
|
|
ca = *catmp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load private key
|
2020-01-18 22:45:28 +00:00
|
|
|
if fd, errr := os.Open(CAPrivkeyPath()); errr != nil {
|
2018-01-21 13:18:26 +00:00
|
|
|
return priv, ca, errr
|
|
|
|
} else {
|
|
|
|
defer fd.Close()
|
2020-01-18 22:45:28 +00:00
|
|
|
if privkey, errr := ioutil.ReadAll(fd); errr != nil {
|
2018-01-21 13:18:26 +00:00
|
|
|
return priv, ca, errr
|
|
|
|
} else {
|
|
|
|
block, _ := pem.Decode(privkey)
|
|
|
|
if block == nil || block.Type != "EC PRIVATE KEY" {
|
|
|
|
return priv, ca, errors.New("failed to decode PEM block containing EC private key")
|
|
|
|
}
|
|
|
|
|
|
|
|
var decrypted_der []byte
|
|
|
|
if x509.IsEncryptedPEMBlock(block) {
|
|
|
|
decrypted_der, err = x509.DecryptPEMBlock(block, []byte(passwordCA))
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
decrypted_der = block.Bytes
|
|
|
|
}
|
|
|
|
|
2020-01-18 22:45:28 +00:00
|
|
|
if tmppriv, errr := x509.ParseECPrivateKey(decrypted_der); errr != nil {
|
2018-01-21 13:18:26 +00:00
|
|
|
return priv, ca, errr
|
|
|
|
} else if tmppriv == nil {
|
|
|
|
return priv, ca, errors.New("failed to parse private key")
|
|
|
|
} else {
|
|
|
|
priv = *tmppriv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|