func GenerateCertifcate(pkiroot, name string, template *x509.Certificate) error { // TODO(jclerc): check that pki has been init var crtPath string privateKeyPath := filepath.Join(pkiroot, "private", name+".key") if name == "ca" { crtPath = filepath.Join(pkiroot, name+".crt") } else { crtPath = filepath.Join(pkiroot, "issued", name+".crt") } var caCrt *x509.Certificate var caKey *rsa.PrivateKey if _, err := os.Stat(privateKeyPath); err == nil { return fmt.Errorf("a key pair for %v already exists", name) } privateKey, err := GeneratePrivateKey(privateKeyPath) if err != nil { return fmt.Errorf("generate private key: %v", err) } publicKeyBytes, err := asn1.Marshal(*privateKey.Public().(*rsa.PublicKey)) if err != nil { return fmt.Errorf("marshal public key: %v", err) } subjectKeyId := sha1.Sum(publicKeyBytes) template.SubjectKeyId = subjectKeyId[:] template.NotBefore = time.Now() template.SignatureAlgorithm = x509.SHA256WithRSA if template.IsCA { serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { return fmt.Errorf("failed to generate ca serial number: %s", err) } template.SerialNumber = serialNumber template.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageCRLSign template.BasicConstraintsValid = true template.Issuer = template.Subject template.AuthorityKeyId = template.SubjectKeyId caCrt = template caKey = privateKey } else { template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment serialNumber, err := NextNumber(pkiroot, "serial") if err != nil { return fmt.Errorf("get next serial: %v", err) } template.SerialNumber = serialNumber caCrt, caKey, err = GetCA(pkiroot) if err != nil { return fmt.Errorf("get ca: %v", err) } } crt, err := x509.CreateCertificate(rand.Reader, template, caCrt, privateKey.Public(), caKey) if err != nil { return fmt.Errorf("create certificate: %v", err) } crtFile, err := os.Create(crtPath) if err != nil { return fmt.Errorf("create %v: %v", crtPath, err) } defer crtFile.Close() err = pem.Encode(crtFile, &pem.Block{ Type: "CERTIFICATE", Bytes: crt, }) if err != nil { return fmt.Errorf("pem encode crt: %v", err) } // I do not think we have to write the ca.crt in the index if !template.IsCA { WriteIndex(pkiroot, name, template) if err != nil { return fmt.Errorf("write index: %v", err) } } return nil }