// addKeyUsages adds approrpiate key usages to the template given the creation // information func addKeyUsages(creationInfo *creationBundle, certTemplate *x509.Certificate) { certTemplate.KeyUsage = x509.KeyUsage(x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement) if creationInfo.Usage&serverUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageServerAuth) } if creationInfo.Usage&clientUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageClientAuth) } if creationInfo.Usage&codeSigningUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageCodeSigning) } if creationInfo.Usage&emailProtectionUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageEmailProtection) } if creationInfo.IsCA { // Go performs validation not according to spec but according to the Windows // Crypto API, so we add all usages to CA certs certTemplate.KeyUsage = x509.KeyUsage(certTemplate.KeyUsage | x509.KeyUsageCertSign | x509.KeyUsageCRLSign) certTemplate.ExtKeyUsage = []x509.ExtKeyUsage{ x509.ExtKeyUsageAny, x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageCodeSigning, x509.ExtKeyUsageEmailProtection, x509.ExtKeyUsageTimeStamping, x509.ExtKeyUsageOCSPSigning, } } }
func templateWithCA(template *x509.Certificate) *x509.Certificate { template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign template.KeyUsage |= x509.KeyUsageKeyEncipherment template.KeyUsage |= x509.KeyUsageKeyAgreement template.ExtKeyUsage = nil return template }
func TestCheckCert(t *testing.T) { testKey, _ := rsa.GenerateKey(rand.Reader, 1024) checker := newChecker(nil) fc := clock.NewFake() fc.Add(time.Hour * 24 * 90) checker.clock = fc issued := checker.clock.Now().Add(-time.Hour * 24 * 45) goodExpiry := issued.Add(checkPeriod) serial := big.NewInt(1337) // Problems // Blacklsited common name // Expiry period is too long // Basic Constraints aren't set // Wrong key usage (none) rawCert := x509.Certificate{ Subject: pkix.Name{ CommonName: "example.com", }, NotAfter: goodExpiry.AddDate(0, 0, 1), // Period too long DNSNames: []string{"example-a.com"}, SerialNumber: serial, BasicConstraintsValid: false, } brokenCertDer, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) test.AssertNotError(t, err, "Couldn't create certificate") // Problems // Digest doesn't match // Serial doesn't match // Expiry doesn't match cert := core.Certificate{ Status: core.StatusValid, DER: brokenCertDer, Issued: issued, Expires: goodExpiry.AddDate(0, 0, 2), // Expiration doesn't match } problems := checker.checkCert(cert) test.AssertEquals(t, len(problems), 7) // Fix the problems rawCert.Subject.CommonName = "example-a.com" rawCert.NotAfter = goodExpiry rawCert.BasicConstraintsValid = true rawCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth} goodCertDer, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) test.AssertNotError(t, err, "Couldn't create certificate") parsed, err := x509.ParseCertificate(goodCertDer) test.AssertNotError(t, err, "Couldn't parse created certificate") cert.Serial = core.SerialToString(serial) cert.Digest = core.Fingerprint256(goodCertDer) cert.DER = goodCertDer cert.Expires = parsed.NotAfter problems = checker.checkCert(cert) test.AssertEquals(t, len(problems), 0) }
// addKeyUsages adds approrpiate key usages to the template given the creation // information func addKeyUsages(creationInfo *creationBundle, certTemplate *x509.Certificate) { if creationInfo.IsCA { certTemplate.KeyUsage = x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign) return } if creationInfo.Usage&serverUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageServerAuth) } if creationInfo.Usage&clientUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageClientAuth) } if creationInfo.Usage&codeSigningUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageCodeSigning) } if creationInfo.Usage&emailProtectionUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageEmailProtection) } }
func createCertificate(d *schema.ResourceData, template, parent *x509.Certificate, pub crypto.PublicKey, priv interface{}) error { var err error template.NotBefore = time.Now() template.NotAfter = template.NotBefore.Add(time.Duration(d.Get("validity_period_hours").(int)) * time.Hour) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) template.SerialNumber, err = rand.Int(rand.Reader, serialNumberLimit) if err != nil { return fmt.Errorf("failed to generate serial number: %s", err) } keyUsesI := d.Get("allowed_uses").([]interface{}) for _, keyUseI := range keyUsesI { keyUse := keyUseI.(string) if usage, ok := keyUsages[keyUse]; ok { template.KeyUsage |= usage } if usage, ok := extKeyUsages[keyUse]; ok { template.ExtKeyUsage = append(template.ExtKeyUsage, usage) } } if d.Get("is_ca_certificate").(bool) { template.IsCA = true template.SubjectKeyId, err = generateSubjectKeyID(pub) if err != nil { return fmt.Errorf("failed to set subject key identifier: %s", err) } } certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv) if err != nil { return fmt.Errorf("error creating certificate: %s", err) } certPem := string(pem.EncodeToMemory(&pem.Block{Type: pemCertType, Bytes: certBytes})) validFromBytes, err := template.NotBefore.MarshalText() if err != nil { return fmt.Errorf("error serializing validity_start_time: %s", err) } validToBytes, err := template.NotAfter.MarshalText() if err != nil { return fmt.Errorf("error serializing validity_end_time: %s", err) } d.SetId(template.SerialNumber.String()) d.Set("cert_pem", certPem) d.Set("validity_start_time", string(validFromBytes)) d.Set("validity_end_time", string(validToBytes)) return nil }
// GenClientCert generates a client certificate. // The generated certificate will have its extended key usage set to 'client authentication' and will be ready for use in TLS client authentication. // The returned slices are the PEM encoded X.509 certificate and private key pair. func GenClientCert(subject pkix.Name, validFor time.Duration, keyLength int, signingCert, signingKey []byte) (cert, key []byte, err error) { var ( sc, c *x509.Certificate sk, k *rsa.PrivateKey ) if sc, sk, err = parseCertAndKey(signingCert, signingKey); err != nil { return } if c, k, err = createBaseCert(subject, validFor, keyLength); err != nil { return } c.KeyUsage = x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature c.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} c.IsCA = false cert, key, err = signAndEncodeCert(sc, sk, c, k) return }
// templateWithServer adds the capabilities of the certificate to be only used for server auth func templateWithServer(template *x509.Certificate, domain string) *x509.Certificate { template.ExtKeyUsage = append(template.ExtKeyUsage, x509.ExtKeyUsageServerAuth) // abide by the spec - if CN is an IP, put it in the subjectAltName as well ip := net.ParseIP(domain) if ip != nil { template.IPAddresses = []net.IP{ip} // try best guess at DNSNames entries names, err := net.LookupAddr(domain) if err == nil && len(names) > 0 { template.DNSNames = names } return template } if domain != "" { template.Subject.CommonName = domain template.DNSNames = []string{domain} } return template }
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) { pub := template.PublicKey encodedpub, err := x509.MarshalPKIXPublicKey(pub) if err != nil { return } pubhash := sha1.New() pubhash.Write(encodedpub) if profile == nil { profile = s.Policy.Default } var ( eku []x509.ExtKeyUsage ku x509.KeyUsage expiry time.Duration crlURL, ocspURL string ) // The third value returned from Usages is a list of unknown key usages. // This should be used when validating the profile at load, and isn't used // here. ku, eku, _ = profile.Usages() expiry = profile.Expiry if profile.IssuerURL == nil { profile.IssuerURL = s.Policy.Default.IssuerURL } if ku == 0 && len(eku) == 0 { err = cferr.New(cferr.PolicyError, cferr.NoKeyUsages, errors.New("no key usage available")) return } if expiry == 0 { expiry = s.Policy.Default.Expiry } if crlURL = profile.CRL; crlURL == "" { crlURL = s.Policy.Default.CRL } if ocspURL = profile.OCSP; ocspURL == "" { ocspURL = s.Policy.Default.OCSP } now := time.Now() serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) if err != nil { err = cferr.New(cferr.CertificateError, cferr.Unknown, err) } template.SerialNumber = serialNumber template.NotBefore = now.Add(-5 * time.Minute).UTC() template.NotAfter = now.Add(expiry).UTC() template.KeyUsage = ku template.ExtKeyUsage = eku template.BasicConstraintsValid = true template.IsCA = profile.CA template.SubjectKeyId = pubhash.Sum(nil) if ocspURL != "" { template.OCSPServer = []string{ocspURL} } if crlURL != "" { template.CRLDistributionPoints = []string{crlURL} } if len(profile.IssuerURL) != 0 { template.IssuingCertificateURL = profile.IssuerURL } var initRoot bool if s.CA == nil { if !template.IsCA { err = cferr.New(cferr.PolicyError, cferr.InvalidRequest, nil) return } template.DNSNames = nil s.CA = template initRoot = true template.MaxPathLen = 2 } else if template.IsCA { template.MaxPathLen = 1 template.DNSNames = nil } derBytes, err := x509.CreateCertificate(rand.Reader, template, s.CA, pub, s.Priv) if err != nil { return } if initRoot { s.CA, err = x509.ParseCertificate(derBytes) if err != nil { err = cferr.New(cferr.CertificateError, cferr.ParseFailed, err) return } } cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) return }
func GenerateFakeX509Certificate(certType string) (string, string) { priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) if err != nil { logging.GetLogger().Fatal("ECDSA GenerateKey failed : " + err.Error()) } serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { logging.GetLogger().Fatal("Serial number generation error : " + err.Error()) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Skydive Co"}, }, NotBefore: time.Now(), NotAfter: time.Now().Add(1 * time.Hour), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, BasicConstraintsValid: true, } if certType == "server" { template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} } else { template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} } hosts := strings.Split("127.0.0.1,::1", ",") for _, h := range hosts { if ip := net.ParseIP(h); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) } else { template.DNSNames = append(template.DNSNames, h) } } template.DNSNames = append(template.DNSNames, "localhost") template.EmailAddresses = append(template.EmailAddresses, "*****@*****.**") /* Generate CA */ template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign /* Certificate */ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) if err != nil { logging.GetLogger().Fatalf("Failed to create certificate: %s", err) } basedir, err := ioutil.TempDir("", "skydive-keys") if err != nil { logging.GetLogger().Fatal("can't create tempdir skydive-keys") } certFilename := filepath.Join(basedir, "cert.pem") certOut, err := os.Create(certFilename) if err != nil { logging.GetLogger().Fatalf("failed to open %s for writing: %s", certFilename, err) } pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) certOut.Close() /* Private Key */ privKeyFilename := filepath.Join(basedir, "key.pem") keyOut, err := os.OpenFile(privKeyFilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { logging.GetLogger().Fatalf("failed to open %s for writing: %s", privKeyFilename, err) } pem.Encode(keyOut, pemBlockForKey(priv)) keyOut.Close() return certFilename, privKeyFilename }
// GenerateMemCert creates client or server certificate and key pair, // returning them as byte arrays in memory. func GenerateMemCert(client bool) ([]byte, []byte, error) { privk, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { log.Fatalf("failed to generate key") return nil, nil, err } hosts, err := mynames() if err != nil { log.Fatalf("Failed to get my hostname") return nil, nil, err } validFrom := time.Now() validTo := validFrom.Add(10 * 365 * 24 * time.Hour) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { log.Fatalf("failed to generate serial number: %s", err) return nil, nil, err } userEntry, err := user.Current() var username string if err == nil { username = userEntry.Username if username == "" { username = "******" } } else { username = "******" } hostname, err := os.Hostname() if err != nil { hostname = "UNKNOWN" } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"linuxcontainers.org"}, CommonName: fmt.Sprintf("%s@%s", username, hostname), }, NotBefore: validFrom, NotAfter: validTo, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, BasicConstraintsValid: true, } if client { template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} } else { template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} } for _, h := range hosts { if ip, _, err := net.ParseCIDR(h); err == nil { if !ip.IsLinkLocalUnicast() && !ip.IsLinkLocalMulticast() { template.IPAddresses = append(template.IPAddresses, ip) } } else { template.DNSNames = append(template.DNSNames, h) } } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privk.PublicKey, privk) if err != nil { log.Fatalf("Failed to create certificate: %s", err) return nil, nil, err } cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) key := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privk)}) return cert, key, nil }
func TestCheckCert(t *testing.T) { saDbMap, err := sa.NewDbMap(vars.DBConnSA, 0) test.AssertNotError(t, err, "Couldn't connect to database") saCleanup := test.ResetSATestDatabase(t) defer func() { saCleanup() }() testKey, _ := rsa.GenerateKey(rand.Reader, 1024) fc := clock.NewFake() fc.Add(time.Hour * 24 * 90) checker := newChecker(saDbMap, fc, pa, expectedValidityPeriod) issued := checker.clock.Now().Add(-time.Hour * 24 * 45) goodExpiry := issued.Add(expectedValidityPeriod) serial := big.NewInt(1337) // Problems // Expiry period is too long // Basic Constraints aren't set // Wrong key usage (none) rawCert := x509.Certificate{ Subject: pkix.Name{ CommonName: "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeexample.com", }, NotBefore: issued, NotAfter: goodExpiry.AddDate(0, 0, 1), // Period too long DNSNames: []string{"example-a.com"}, SerialNumber: serial, BasicConstraintsValid: false, } brokenCertDer, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) test.AssertNotError(t, err, "Couldn't create certificate") // Problems // Digest doesn't match // Serial doesn't match // Expiry doesn't match // Issued doesn't match cert := core.Certificate{ Serial: "8485f2687eba29ad455ae4e31c8679206fec", DER: brokenCertDer, Issued: issued.Add(12 * time.Hour), Expires: goodExpiry.AddDate(0, 0, 2), // Expiration doesn't match } problems := checker.checkCert(cert) problemsMap := map[string]int{ "Stored digest doesn't match certificate digest": 1, "Stored serial doesn't match certificate serial": 1, "Stored expiration doesn't match certificate NotAfter": 1, "Certificate doesn't have basic constraints set": 1, "Certificate has a validity period longer than 2160h0m0s": 1, "Stored issuance date is outside of 6 hour window of certificate NotBefore": 1, "Certificate has incorrect key usage extensions": 1, "Certificate has common name >64 characters long (65)": 1, } for _, p := range problems { _, ok := problemsMap[p] if !ok { t.Errorf("Found unexpected problem '%s'.", p) } delete(problemsMap, p) } for k := range problemsMap { t.Errorf("Expected problem but didn't find it: '%s'.", k) } test.AssertEquals(t, len(problems), 8) // Same settings as above, but the stored serial number in the DB is invalid. cert.Serial = "not valid" problems = checker.checkCert(cert) foundInvalidSerialProblem := false for _, p := range problems { if p == "Stored serial is invalid" { foundInvalidSerialProblem = true } } test.Assert(t, foundInvalidSerialProblem, "Invalid certificate serial number in DB did not trigger problem.") // Fix the problems rawCert.Subject.CommonName = "example-a.com" rawCert.NotAfter = goodExpiry rawCert.BasicConstraintsValid = true rawCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth} goodCertDer, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) test.AssertNotError(t, err, "Couldn't create certificate") parsed, err := x509.ParseCertificate(goodCertDer) test.AssertNotError(t, err, "Couldn't parse created certificate") cert.Serial = core.SerialToString(serial) cert.Digest = core.Fingerprint256(goodCertDer) cert.DER = goodCertDer cert.Expires = parsed.NotAfter cert.Issued = parsed.NotBefore problems = checker.checkCert(cert) test.AssertEquals(t, len(problems), 0) }
// WriteNewCerts generates a self-signed certificate pair for use in // locally authorizing clients. If 'server' is true, it writes out certs // which can be used to verify the server, otherwise it writes out certs // clients can use to authorize themselves to the server. func WriteNewCerts(certFile, keyFile string, server bool) error { // Implementation mostly taken from http://golang.org/src/pkg/crypto/tls/generate_cert.go priv, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return fmt.Errorf("failed to generate private key: %v", err) } 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 serial number: %v", err) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Stenographer"}, CommonName: "127.0.0.1", }, NotBefore: time.Now(), NotAfter: time.Now().Add(validFor), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, DNSNames: []string{"localhost"}, IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)}, IsCA: true, // we're self-signed. } var keyFileMode os.FileMode if server { template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} keyFileMode = 0600 } else { template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} keyFileMode = 0640 } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) if err != nil { return fmt.Errorf("Failed to create certificate: %v", err) } // Actually start writing. certOut, err := os.Create(certFile) if err != nil { return fmt.Errorf("failed to open %q for writing: %s", certFile, err) } if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { return fmt.Errorf("could not encode pem: %v", err) } if err := certOut.Close(); err != nil { return fmt.Errorf("could not close cert file: %v", err) } keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, keyFileMode) if err != nil { return fmt.Errorf("failed to open %q for writing: %v", keyFile, err) } if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { return fmt.Errorf("could not encode key: %v", err) } if err := keyOut.Close(); err != nil { return fmt.Errorf("could not close key file: %v", err) } return nil }
func SignNewCertificate(privateKey *PrivateKey, template *x509.Certificate, signer *x509.Certificate, signerPrivateKey *PrivateKey) (*Certificate, error) { if template.PublicKey == nil { rsaPrivateKey, ok := privateKey.Key.(*rsa.PrivateKey) if ok { template.PublicKey = rsaPrivateKey.Public() } } if template.PublicKey == nil { return nil, fmt.Errorf("PublicKey not set, and cannot be determined from %T", privateKey) } now := time.Now() if template.NotBefore.IsZero() { template.NotBefore = now.Add(time.Hour * -48) } if template.NotAfter.IsZero() { template.NotAfter = now.Add(time.Hour * 10 * 365 * 24) } if template.SerialNumber == nil { serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := crypto_rand.Int(crypto_rand.Reader, serialNumberLimit) if err != nil { return nil, fmt.Errorf("error generating certificate serial number: %s", err) } template.SerialNumber = serialNumber } var parent *x509.Certificate if signer != nil { parent = signer } else { parent = template signerPrivateKey = privateKey } if template.KeyUsage == 0 { template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment } if template.ExtKeyUsage == nil { template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} } //c.SignatureAlgorithm = do we want to overrride? certificateData, err := x509.CreateCertificate(crypto_rand.Reader, template, parent, template.PublicKey, signerPrivateKey.Key) if err != nil { return nil, fmt.Errorf("error creating certificate: %v", err) } c := &Certificate{} c.PublicKey = template.PublicKey cert, err := x509.ParseCertificate(certificateData) if err != nil { return nil, fmt.Errorf("error parsing certificate: %v", err) } c.Certificate = cert return c, nil }
func TestCheckCert(t *testing.T) { saDbMap, err := sa.NewDbMap(saDbConnStr) test.AssertNotError(t, err, "Couldn't connect to database") saCleanup := test.ResetTestDatabase(t, saDbMap.Db) paDbMap, err := sa.NewDbMap(paDbConnStr) test.AssertNotError(t, err, "Couldn't connect to policy database") paCleanup := test.ResetTestDatabase(t, paDbMap.Db) defer func() { saCleanup() paCleanup() }() testKey, _ := rsa.GenerateKey(rand.Reader, 1024) fc := clock.NewFake() fc.Add(time.Hour * 24 * 90) checker := newChecker(saDbMap, paDbMap, fc, false) issued := checker.clock.Now().Add(-time.Hour * 24 * 45) goodExpiry := issued.Add(checkPeriod) serial := big.NewInt(1337) // Problems // Expiry period is too long // Basic Constraints aren't set // Wrong key usage (none) rawCert := x509.Certificate{ Subject: pkix.Name{ CommonName: "example.com", }, NotBefore: issued, NotAfter: goodExpiry.AddDate(0, 0, 1), // Period too long DNSNames: []string{"example-a.com"}, SerialNumber: serial, BasicConstraintsValid: false, } brokenCertDer, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) test.AssertNotError(t, err, "Couldn't create certificate") // Problems // Digest doesn't match // Serial doesn't match // Expiry doesn't match // Issued doesn't match cert := core.Certificate{ DER: brokenCertDer, Issued: issued.Add(12 * time.Hour), Expires: goodExpiry.AddDate(0, 0, 2), // Expiration doesn't match } problems := checker.checkCert(cert) fmt.Println(strings.Join(problems, "\n")) test.AssertEquals(t, len(problems), 7) // Fix the problems rawCert.Subject.CommonName = "example-a.com" rawCert.NotAfter = goodExpiry rawCert.BasicConstraintsValid = true rawCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth} goodCertDer, err := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey) test.AssertNotError(t, err, "Couldn't create certificate") parsed, err := x509.ParseCertificate(goodCertDer) test.AssertNotError(t, err, "Couldn't parse created certificate") cert.Serial = core.SerialToString(serial) cert.Digest = core.Fingerprint256(goodCertDer) cert.DER = goodCertDer cert.Expires = parsed.NotAfter cert.Issued = parsed.NotBefore problems = checker.checkCert(cert) test.AssertEquals(t, len(problems), 0) }
// FillTemplate is a utility function that tries to load as much of // the certificate template as possible from the profiles and current // template. It fills in the key uses, expiration, revocation URLs // and SKI. func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile) error { ski, err := ComputeSKI(template) var ( eku []x509.ExtKeyUsage ku x509.KeyUsage backdate time.Duration expiry time.Duration notBefore time.Time notAfter time.Time crlURL, ocspURL string ) // The third value returned from Usages is a list of unknown key usages. // This should be used when validating the profile at load, and isn't used // here. ku, eku, _ = profile.Usages() if profile.IssuerURL == nil { profile.IssuerURL = defaultProfile.IssuerURL } if ku == 0 && len(eku) == 0 { return cferr.New(cferr.PolicyError, cferr.NoKeyUsages) } if expiry = profile.Expiry; expiry == 0 { expiry = defaultProfile.Expiry } if crlURL = profile.CRL; crlURL == "" { crlURL = defaultProfile.CRL } if ocspURL = profile.OCSP; ocspURL == "" { ocspURL = defaultProfile.OCSP } if backdate = profile.Backdate; backdate == 0 { backdate = -5 * time.Minute } else { backdate = -1 * profile.Backdate } if !profile.NotBefore.IsZero() { notBefore = profile.NotBefore.UTC() } else { notBefore = time.Now().Round(time.Minute).Add(backdate).UTC() } if !profile.NotAfter.IsZero() { notAfter = profile.NotAfter.UTC() } else { notAfter = notBefore.Add(expiry).UTC() } template.NotBefore = notBefore template.NotAfter = notAfter template.KeyUsage = ku template.ExtKeyUsage = eku template.BasicConstraintsValid = true template.IsCA = profile.CA template.SubjectKeyId = ski if ocspURL != "" { template.OCSPServer = []string{ocspURL} } if crlURL != "" { template.CRLDistributionPoints = []string{crlURL} } if len(profile.IssuerURL) != 0 { template.IssuingCertificateURL = profile.IssuerURL } if len(profile.Policies) != 0 { err = addPolicies(template, profile.Policies) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err) } } if profile.OCSPNoCheck { ocspNoCheckExtension := pkix.Extension{ Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5}, Critical: false, Value: []byte{0x05, 0x00}, } template.ExtraExtensions = append(template.ExtraExtensions, ocspNoCheckExtension) } return nil }
func main() { organisation := "acmecorp" // Common Name for the certificate. The common name // can be anything, but is usually set to the server's primary // DNS name. Even if you plan to connect via IP address you // should specify the DNS name here. commonName := "localhost" // additional DNS names and IP // addresses that clients may use to connect to the server. If // you plan to connect to the server via IP address and not DNS // then you must specify those IP addresses here. ipaddressOrDNSNames := []string{"127.0.0.1", "localhost"} // How long should the certificate be valid for? A year (365 // days) is usual but requires the certificate to be regenerated // within a year or the certificate will cease working. validInDays := 365 template := x509.Certificate{ Subject: pkix.Name{ Organization: []string{organisation}, CommonName: commonName, }, NotBefore: time.Now(), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, IsCA: true, } for _, val := range ipaddressOrDNSNames { if ip := net.ParseIP(val); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) } else { template.DNSNames = append(template.DNSNames, val) } } template.NotAfter = template.NotBefore.Add(time.Duration(validInDays) * time.Hour * 24) spew.Dump(template) server_path := "../server" client_path := "../client" if _, err := os.Stat(server_path); os.IsNotExist(err) { os.Mkdir(server_path, 0700) } if _, err := os.Stat(client_path); os.IsNotExist(err) { os.Mkdir(client_path, 0700) } generateCerts(template, server_path) template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} generateCerts(template, client_path) }
func CreateSelfSignedCert(d *schema.ResourceData, meta interface{}) error { keyAlgoName := d.Get("key_algorithm").(string) var keyFunc keyParser var ok bool if keyFunc, ok = keyParsers[keyAlgoName]; !ok { return fmt.Errorf("invalid key_algorithm %#v", keyAlgoName) } keyBlock, _ := pem.Decode([]byte(d.Get("private_key_pem").(string))) if keyBlock == nil { return fmt.Errorf("no PEM block found in private_key_pem") } key, err := keyFunc(keyBlock.Bytes) if err != nil { return fmt.Errorf("failed to decode private_key_pem: %s", err) } notBefore := time.Now() notAfter := notBefore.Add(time.Duration(d.Get("validity_period_hours").(int)) * time.Hour) 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 serial number: %s", err) } subjectConfs := d.Get("subject").([]interface{}) if len(subjectConfs) != 1 { return fmt.Errorf("must have exactly one 'subject' block") } subjectConf := subjectConfs[0].(map[string]interface{}) subject, err := nameFromResourceData(subjectConf) if err != nil { return fmt.Errorf("invalid subject block: %s", err) } cert := x509.Certificate{ SerialNumber: serialNumber, Subject: *subject, NotBefore: notBefore, NotAfter: notAfter, BasicConstraintsValid: true, } keyUsesI := d.Get("allowed_uses").([]interface{}) for _, keyUseI := range keyUsesI { keyUse := keyUseI.(string) if usage, ok := keyUsages[keyUse]; ok { cert.KeyUsage |= usage } if usage, ok := extKeyUsages[keyUse]; ok { cert.ExtKeyUsage = append(cert.ExtKeyUsage, usage) } } dnsNamesI := d.Get("dns_names").([]interface{}) for _, nameI := range dnsNamesI { cert.DNSNames = append(cert.DNSNames, nameI.(string)) } ipAddressesI := d.Get("ip_addresses").([]interface{}) for _, ipStrI := range ipAddressesI { ip := net.ParseIP(ipStrI.(string)) if ip == nil { return fmt.Errorf("invalid IP address %#v", ipStrI.(string)) } cert.IPAddresses = append(cert.IPAddresses, ip) } if d.Get("is_ca_certificate").(bool) { cert.IsCA = true } certBytes, err := x509.CreateCertificate(rand.Reader, &cert, &cert, publicKey(key), key) if err != nil { fmt.Errorf("Error creating certificate: %s", err) } certPem := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})) validFromBytes, err := notBefore.MarshalText() if err != nil { return fmt.Errorf("error serializing validity_start_time: %s", err) } validToBytes, err := notAfter.MarshalText() if err != nil { return fmt.Errorf("error serializing validity_end_time: %s", err) } d.SetId(serialNumber.String()) d.Set("cert_pem", certPem) d.Set("validity_start_time", string(validFromBytes)) d.Set("validity_end_time", string(validToBytes)) return nil }
// WriteNewCerts generates a self-signed certificate pair for use in // locally authorizing clients. If 'server' is true, it writes out certs // which can be used to verify the server, otherwise it writes out certs // clients can use to authorize themselves to the server. func WriteNewCerts(certFile, keyFile string, caCertFile string, crtType CertType) error { var caCert *x509.Certificate 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 serial number: %v", err) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Stenographer"}, CommonName: "127.0.0.1", }, NotBefore: time.Now(), NotAfter: time.Now().Add(validFor), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, DNSNames: []string{"localhost"}, IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)}, IsCA: false, // we're not self-signed. } caCert = template if caCertFile != "" { if certBytes, err := ioutil.ReadFile(caCertFile); err != nil { return nil, fmt.Errorf("could not ca read cert file: %v", err) } else if block, _ := pem.Decode(certBytes); block == nil { return nil, fmt.Errorf("could not get cert pem block: %v", err) } else if caCert, err = x509.ParseCertificate(block.Bytes); err != nil { return nil, fmt.Errorf("could not parse cert: %v", err) } } var keyFileMode os.FileMode switch crtType { case CA: keyFileMode = 0600 template.IsCA = true case Server: template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} keyFileMode = 0600 case Client: template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} keyFileMode = 0640 } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &caCert, &priv.PublicKey, priv) if err != nil { return fmt.Errorf("Failed to create certificate: %v", err) } // Actually start writing. certOut, err := os.Create(certFile) if err != nil { return fmt.Errorf("failed to open %q for writing: %s", certFile, err) } if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { return fmt.Errorf("could not encode pem: %v", err) } if err := certOut.Close(); err != nil { return fmt.Errorf("could not close cert file: %v", err) } keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, keyFileMode) if err != nil { return fmt.Errorf("failed to open %q for writing: %v", keyFile, err) } if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { return fmt.Errorf("could not encode key: %v", err) } if err := keyOut.Close(); err != nil { return fmt.Errorf("could not close key file: %v", err) } return nil }
func main() { flag.Parse() privateKey, err := rsa.GenerateKey(rand.Reader, *rsaBits) if err != nil { log.Fatalf("failed to generate private key: %s", err) return } notBefore := time.Now() notAfter := notBefore.Add(*validFor) template := x509.Certificate{ SerialNumber: new(big.Int).SetInt64(0), Subject: pkix.Name{ Country: []string{"AU"}, Province: []string{"NSW"}, Locality: []string{"Sydney"}, CommonName: *commonName, Organization: []string{*organization}, //OrganizationalUnit: []string{"Async Certification Authority"}, }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, //ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } // DNS names here // self signed case. too lazy to write down types parent := &template // default to self-signed signingKey := &privateKey if len(*parentDir) > 0 { asn1Cert, err := ioutil.ReadFile(*parentDir + "/cert.cer") if err != nil { log.Fatal("failed to read parent cert", err) } parentCert, err := x509.ParseCertificate(asn1Cert) asn1Key, err := ioutil.ReadFile(*parentDir + "/key.der") if err != nil { log.Fatal("failed to read private key", err) } parentKey, err := x509.ParsePKCS1PrivateKey(asn1Key) if err != nil { log.Fatal("failed to parse private key", err) } parent = parentCert signingKey = &parentKey } switch *certType { case "ca": template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign // AGL says whole chain must either have no key usage specified or // client auth all the way or have extended any. Due to bug in for loop, // need to build go from source after 10 dec 2013. // https://groups.google.com/forum/#!topic/golang-nuts/753fOH9mQz0 // update: https://code.google.com/p/go/issues/detail?id=7423 // can do custom with "RequireAnyClientCert and then verify the chain from tls.Conn.ConnectionState()" // http://stackoverflow.com/questions/20875626/tls-clientauth-requires-extkeyusageclientauth-through-whole-certificate-chain template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny} case "client": template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} case "server": template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} } derBytes, err := x509.CreateCertificate(rand.Reader, &template, parent, &privateKey.PublicKey, *signingKey) if err != nil { log.Fatalf("Failed to create certificate: %s", err) return } err = ioutil.WriteFile(*dstDir+"/cert.cer", derBytes, 0600) if err != nil { log.Fatalf("failed to open cert.cer for writing: %s", err) } err = ioutil.WriteFile(*dstDir+"/key.der", x509.MarshalPKCS1PrivateKey(privateKey), 0600) if err != nil { log.Fatalf("failed to open key for writing: %s", err) } }
// templateAsClientOnly restricts the capabilities of the certificate to be only used for client auth func templateAsClientOnly(template *x509.Certificate) *x509.Certificate { template.KeyUsage = x509.KeyUsageDigitalSignature template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth} return template }