func selfSignMain(args []string, c cli.Config) (err error) { if c.Hostname == "" && !c.IsCA { c.Hostname, args, err = cli.PopFirstArgument(args) if err != nil { return } } csrFile, args, err := cli.PopFirstArgument(args) if err != nil { return } csrFileBytes, err := cli.ReadStdin(csrFile) if err != nil { return } var req = csr.New() err = json.Unmarshal(csrFileBytes, req) if err != nil { return } var key, csrPEM []byte g := &csr.Generator{Validator: genkey.Validator} csrPEM, key, err = g.ProcessRequest(req) if err != nil { key = nil return } priv, err := helpers.ParsePrivateKeyPEM(key) if err != nil { key = nil return } var profile *config.SigningProfile // If there is a config, use its signing policy. Otherwise, leave policy == nil // and NewSigner will use DefaultConfig(). if c.CFG != nil { if c.Profile != "" && c.CFG.Signing.Profiles != nil { profile = c.CFG.Signing.Profiles[c.Profile] } } if profile == nil { profile = config.DefaultConfig() profile.Expiry = 2190 * time.Hour } cert, err := selfsign.Sign(priv, csrPEM, profile) if err != nil { key = nil priv = nil return } fmt.Fprintf(os.Stderr, `*** WARNING *** Self-signed certificates are dangerous. Use this self-signed certificate at your own risk. It is strongly recommended that these certificates NOT be used in production. *** WARNING *** `) cli.PrintCert(key, csrPEM, cert) return }
// Sign creates a new self-signed certificate. func Sign(priv crypto.Signer, csrPEM []byte, profile *config.SigningProfile) ([]byte, error) { if profile == nil { return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("no profile for self-signing")) } p, _ := pem.Decode(csrPEM) if p == nil || p.Type != "CERTIFICATE REQUEST" { return nil, cferr.New(cferr.CSRError, cferr.BadRequest) } template, err := parseCertificateRequest(priv, p.Bytes) if err != nil { return nil, err } pub := template.PublicKey encodedpub, err := x509.MarshalPKIXPublicKey(pub) if err != nil { return nil, err } var subPKI subjectPublicKeyInfo _, err = asn1.Unmarshal(encodedpub, &subPKI) if err != nil { return nil, err } pubhash := sha1.New() pubhash.Write(subPKI.SubjectPublicKey.Bytes) 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 ku == 0 && len(eku) == 0 { err = cferr.New(cferr.PolicyError, cferr.NoKeyUsages) return nil, err } if expiry == 0 { expiry = threeMonths } now := time.Now() serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.Unknown, err) return nil, 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 } cert, err := x509.CreateCertificate(rand.Reader, template, template, pub, priv) if err != nil { return nil, err } cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}) return cert, nil }
// 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 }