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 os.Mkdir(PKIDir, 0777) os.Mkdir(path.Join(PKIDir, "shared"), 0777) 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 if fd, errr := os.Open(CACertPath()); errr != nil { return priv, ca, errr } else { defer fd.Close() if cert, errr := ioutil.ReadAll(fd); errr != nil { 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") } if catmp, errr := x509.ParseCertificate(block.Bytes); errr != nil { return priv, ca, errr } else if catmp == nil { return priv, ca, errors.New("failed to parse certificate") } else { ca = *catmp } } } // Load private key if fd, errr := os.Open(CAPrivkeyPath()); errr != nil { return priv, ca, errr } else { defer fd.Close() if privkey, errr := ioutil.ReadAll(fd); errr != nil { 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 } if tmppriv, errr := x509.ParseECPrivateKey(decrypted_der); errr != nil { return priv, ca, errr } else if tmppriv == nil { return priv, ca, errors.New("failed to parse private key") } else { priv = *tmppriv } } } return }