Update github.com/cloudflare/cfssl and github.com/google/certificate-transparency (#2032)
Updates `github.com/cloudflare/cfssl` and `github.com/google/certificate-transparency/go` to current master. CFSSL has re-structured some of the `signer/local` code which should be given a once-over. Otherwise everything seems mostly benign and/or doesn't affect our usage. Vendored tests pass.
This commit is contained in:
parent
8cd74bf766
commit
887618effc
|
|
@ -13,59 +13,73 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/auth",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/certdb",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/config",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/crypto/pkcs7",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/csr",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/errors",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/helpers",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/helpers/derhelpers",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/info",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/log",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/ocsp",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/ocsp/config",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/signer",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/cloudflare/cfssl/signer/local",
|
||||
"Rev": "31c7d21b04cb891fbe30e001a093addbb37c8192"
|
||||
"Comment": "1.2.0-70-gdeed6ed",
|
||||
"Rev": "deed6eddef4f5e28c14d26d3c25b1fc454ce8baf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codegangsta/cli",
|
||||
|
|
@ -99,23 +113,23 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/certificate-transparency/go",
|
||||
"Rev": "025a5cab06f6a819c455d9fdc9e2a1b6d0982284"
|
||||
"Rev": "0f6e3d1d1ba4d03fdaab7cd716f36255c2e48341"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/certificate-transparency/go/asn1",
|
||||
"Rev": "025a5cab06f6a819c455d9fdc9e2a1b6d0982284"
|
||||
"Rev": "0f6e3d1d1ba4d03fdaab7cd716f36255c2e48341"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/certificate-transparency/go/client",
|
||||
"Rev": "025a5cab06f6a819c455d9fdc9e2a1b6d0982284"
|
||||
"Rev": "0f6e3d1d1ba4d03fdaab7cd716f36255c2e48341"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/certificate-transparency/go/x509",
|
||||
"Rev": "025a5cab06f6a819c455d9fdc9e2a1b6d0982284"
|
||||
"Rev": "0f6e3d1d1ba4d03fdaab7cd716f36255c2e48341"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/certificate-transparency/go/x509/pkix",
|
||||
"Rev": "025a5cab06f6a819c455d9fdc9e2a1b6d0982284"
|
||||
"Rev": "0f6e3d1d1ba4d03fdaab7cd716f36255c2e48341"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jmhodges/clock",
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ func NewLog(uri, b64PK string) (*Log, error) {
|
|||
if strings.HasSuffix(uri, "/") {
|
||||
uri = uri[0 : len(uri)-2]
|
||||
}
|
||||
client := ctClient.New(uri)
|
||||
client := ctClient.New(uri, nil)
|
||||
|
||||
pkBytes, err := base64.StdEncoding.DecodeString(b64PK)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -16,21 +16,26 @@ A database is required for the following:
|
|||
|
||||
This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends.
|
||||
Currently supported:
|
||||
- SQLite in sqlite
|
||||
- MySQL in mysql
|
||||
- PostgreSQL in pg
|
||||
- SQLite in sqlite
|
||||
|
||||
### Get goose
|
||||
|
||||
go get https://bitbucket.org/liamstask/goose/
|
||||
go get bitbucket.org/liamstask/goose/cmd/goose
|
||||
|
||||
### Use goose to start and terminate a SQLite DB
|
||||
To start a SQLite DB using goose:
|
||||
### Use goose to start and terminate a MySQL DB
|
||||
To start a MySQL using goose:
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up'
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql up
|
||||
|
||||
To tear down a SQLite DB using goose
|
||||
To tear down a MySQL DB using goose
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql down
|
||||
|
||||
Note: the administration of MySQL DB is not included. We assume
|
||||
the databases being connected to are already created and access control
|
||||
is properly handled.
|
||||
|
||||
### Use goose to start and terminate a PostgreSQL DB
|
||||
To start a PostgreSQL using goose:
|
||||
|
|
@ -43,7 +48,16 @@ To tear down a PostgreSQL DB using goose
|
|||
|
||||
Note: the administration of PostgreSQL DB is not included. We assume
|
||||
the databases being connected to are already created and access control
|
||||
are properly handled.
|
||||
is properly handled.
|
||||
|
||||
### Use goose to start and terminate a SQLite DB
|
||||
To start a SQLite DB using goose:
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up
|
||||
|
||||
To tear down a SQLite DB using goose
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
|
||||
|
||||
## CFSSL Configuration
|
||||
|
||||
|
|
@ -55,4 +69,3 @@ JSON dictionary:
|
|||
or
|
||||
|
||||
{"driver":"postgres","data_source":"postgres://user:password@host/db"}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/json"
|
||||
|
|
@ -86,6 +87,8 @@ type SigningProfile struct {
|
|||
Provider auth.Provider
|
||||
RemoteProvider auth.Provider
|
||||
RemoteServer string
|
||||
RemoteCAs *x509.CertPool
|
||||
ClientCert *tls.Certificate
|
||||
CSRWhitelist *CSRWhitelist
|
||||
NameWhitelist *regexp.Regexp
|
||||
ExtensionWhitelist map[string]bool
|
||||
|
|
@ -303,6 +306,44 @@ func (p *Signing) OverrideRemotes(remote string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetClientCertKeyPairFromFile updates the properties to set client certificates for mutual
|
||||
// authenticated TLS remote requests
|
||||
func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error {
|
||||
if certFile != "" && keyFile != "" {
|
||||
cert, err := helpers.LoadClientCertificate(certFile, keyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, profile := range p.Profiles {
|
||||
profile.ClientCert = cert
|
||||
}
|
||||
p.Default.ClientCert = cert
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRemoteCAsFromFile reads root CAs from file and updates the properties to set remote CAs for TLS
|
||||
// remote requests
|
||||
func (p *Signing) SetRemoteCAsFromFile(caFile string) error {
|
||||
if caFile != "" {
|
||||
remoteCAs, err := helpers.LoadPEMCertPool(caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.SetRemoteCAs(remoteCAs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRemoteCAs updates the properties to set remote CAs for TLS
|
||||
// remote requests
|
||||
func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) {
|
||||
for _, profile := range p.Profiles {
|
||||
profile.RemoteCAs = remoteCAs
|
||||
}
|
||||
p.Default.RemoteCAs = remoteCAs
|
||||
}
|
||||
|
||||
// NeedsRemoteSigner returns true if one of the profiles has a remote set
|
||||
func (p *Signing) NeedsRemoteSigner() bool {
|
||||
for _, profile := range p.Profiles {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"net"
|
||||
|
|
@ -176,6 +177,12 @@ func (cr *CertificateRequest) Name() pkix.Name {
|
|||
return name
|
||||
}
|
||||
|
||||
// BasicConstraints CSR information RFC 5280, 4.2.1.9
|
||||
type BasicConstraints struct {
|
||||
IsCA bool `asn1:"optional"`
|
||||
MaxPathLen int `asn1:"optional,default:-1"`
|
||||
}
|
||||
|
||||
// ParseRequest takes a certificate request and generates a key and
|
||||
// CSR from it. It does no validation -- caveat emptor. It will,
|
||||
// however, fail if the key request is not valid (i.e., an unsupported
|
||||
|
|
@ -218,34 +225,11 @@ func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
|
|||
panic("Generate should have failed to produce a valid key.")
|
||||
}
|
||||
|
||||
var tpl = x509.CertificateRequest{
|
||||
Subject: req.Name(),
|
||||
SignatureAlgorithm: req.KeyRequest.SigAlgo(),
|
||||
}
|
||||
|
||||
for i := range req.Hosts {
|
||||
if ip := net.ParseIP(req.Hosts[i]); ip != nil {
|
||||
tpl.IPAddresses = append(tpl.IPAddresses, ip)
|
||||
} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
|
||||
tpl.EmailAddresses = append(tpl.EmailAddresses, req.Hosts[i])
|
||||
} else {
|
||||
tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
|
||||
}
|
||||
}
|
||||
|
||||
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
|
||||
csr, err = Generate(priv.(crypto.Signer), req)
|
||||
if err != nil {
|
||||
log.Errorf("failed to generate a CSR: %v", err)
|
||||
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
|
||||
return
|
||||
}
|
||||
block := pem.Block{
|
||||
Type: "CERTIFICATE REQUEST",
|
||||
Bytes: csr,
|
||||
}
|
||||
|
||||
log.Info("encoded CSR")
|
||||
csr = pem.EncodeToMemory(&block)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +363,7 @@ func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
|
|||
// Generate creates a new CSR from a CertificateRequest structure and
|
||||
// an existing key. The KeyRequest field is ignored.
|
||||
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
|
||||
sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256)
|
||||
sigAlgo := helpers.SignerAlgo(priv)
|
||||
if sigAlgo == x509.UnknownSignatureAlgorithm {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
|
||||
}
|
||||
|
|
@ -399,6 +383,14 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
|
|||
}
|
||||
}
|
||||
|
||||
if req.CA != nil {
|
||||
err = appendCAInfoToCSR(req.CA, &tpl)
|
||||
if err != nil {
|
||||
err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
|
||||
if err != nil {
|
||||
log.Errorf("failed to generate a CSR: %v", err)
|
||||
|
|
@ -414,3 +406,26 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
|
|||
csr = pem.EncodeToMemory(&block)
|
||||
return
|
||||
}
|
||||
|
||||
// appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
|
||||
func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
|
||||
pathlen := reqConf.PathLength
|
||||
if pathlen == 0 && !reqConf.PathLenZero {
|
||||
pathlen = -1
|
||||
}
|
||||
val, err := asn1.Marshal(BasicConstraints{true, pathlen})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
csr.ExtraExtensions = []pkix.Extension{
|
||||
{
|
||||
Id: asn1.ObjectIdentifier{2, 5, 29, 19},
|
||||
Value: val,
|
||||
Critical: true,
|
||||
},
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import (
|
|||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
|
|
@ -310,11 +312,23 @@ func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, e
|
|||
|
||||
// LoadPEMCertPool loads a pool of PEM certificates from file.
|
||||
func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
|
||||
if certsFile == "" {
|
||||
return nil, nil
|
||||
}
|
||||
pemCerts, err := ioutil.ReadFile(certsFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return PEMToCertPool(pemCerts)
|
||||
}
|
||||
|
||||
// PEMToCertPool concerts PEM certificates to a CertPool.
|
||||
func PEMToCertPool(pemCerts []byte) (*x509.CertPool, error) {
|
||||
if len(pemCerts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
if !certPool.AppendCertsFromPEM(pemCerts) {
|
||||
return nil, errors.New("failed to load cert pool")
|
||||
|
|
@ -446,28 +460,28 @@ func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
|
|||
return csrObject, nil
|
||||
}
|
||||
|
||||
// SignerAlgo returns an X.509 signature algorithm corresponding to
|
||||
// the crypto.Hash provided from a crypto.Signer.
|
||||
func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm {
|
||||
switch priv.Public().(type) {
|
||||
// SignerAlgo returns an X.509 signature algorithm from a crypto.Signer.
|
||||
func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
|
||||
switch pub := priv.Public().(type) {
|
||||
case *rsa.PublicKey:
|
||||
switch h {
|
||||
case crypto.SHA512:
|
||||
bitLength := pub.N.BitLen()
|
||||
switch {
|
||||
case bitLength >= 4096:
|
||||
return x509.SHA512WithRSA
|
||||
case crypto.SHA384:
|
||||
case bitLength >= 3072:
|
||||
return x509.SHA384WithRSA
|
||||
case crypto.SHA256:
|
||||
case bitLength >= 2048:
|
||||
return x509.SHA256WithRSA
|
||||
default:
|
||||
return x509.SHA1WithRSA
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
switch h {
|
||||
case crypto.SHA512:
|
||||
switch pub.Curve {
|
||||
case elliptic.P521():
|
||||
return x509.ECDSAWithSHA512
|
||||
case crypto.SHA384:
|
||||
case elliptic.P384():
|
||||
return x509.ECDSAWithSHA384
|
||||
case crypto.SHA256:
|
||||
case elliptic.P256():
|
||||
return x509.ECDSAWithSHA256
|
||||
default:
|
||||
return x509.ECDSAWithSHA1
|
||||
|
|
@ -476,3 +490,29 @@ func SignerAlgo(priv crypto.Signer, h crypto.Hash) x509.SignatureAlgorithm {
|
|||
return x509.UnknownSignatureAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
// LoadClientCertificate load key/certificate from pem files
|
||||
func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, error) {
|
||||
if certFile != "" && keyFile != "" {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
log.Critical("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Client certificate loaded ")
|
||||
return &cert, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CreateTLSConfig creates a tls.Config object from certs and roots
|
||||
func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Config {
|
||||
var certs []tls.Certificate
|
||||
if cert != nil {
|
||||
certs = []tls.Certificate{*cert}
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: certs,
|
||||
RootCAs: remoteCAs,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
|
@ -63,13 +62,6 @@ func SetLogger(logger SyslogWriter) {
|
|||
syslogWriter = logger
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Only define loglevel flag once.
|
||||
if flag.Lookup("loglevel") == nil {
|
||||
flag.IntVar(&Level, "loglevel", LevelInfo, "Log level (0 = DEBUG, 5 = FATAL)")
|
||||
}
|
||||
}
|
||||
|
||||
func print(l int, msg string) {
|
||||
if l >= Level {
|
||||
if syslogWriter != nil {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,11 @@ func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signe
|
|||
}
|
||||
|
||||
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
|
||||
var distPoints = template.CRLDistributionPoints
|
||||
err = signer.FillTemplate(template, s.policy.Default, profile)
|
||||
if distPoints != nil && len(distPoints) > 0 {
|
||||
template.CRLDistributionPoints = distPoints
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -111,10 +115,7 @@ func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile
|
|||
template.EmailAddresses = nil
|
||||
s.ca = template
|
||||
initRoot = true
|
||||
template.MaxPathLen = signer.MaxPathLen
|
||||
template.MaxPathLenZero = signer.MaxPathLenZero
|
||||
} else if template.IsCA {
|
||||
template.MaxPathLen = 1
|
||||
template.DNSNames = nil
|
||||
template.EmailAddresses = nil
|
||||
}
|
||||
|
|
@ -244,6 +245,26 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
if req.CRLOverride != "" {
|
||||
safeTemplate.CRLDistributionPoints = []string{req.CRLOverride}
|
||||
}
|
||||
|
||||
if safeTemplate.IsCA {
|
||||
if !profile.CA {
|
||||
return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
|
||||
}
|
||||
|
||||
if s.ca != nil && s.ca.MaxPathLen > 0 {
|
||||
if safeTemplate.MaxPathLen >= s.ca.MaxPathLen {
|
||||
// do not sign a cert with pathlen > current
|
||||
return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
|
||||
}
|
||||
} else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero {
|
||||
// signer has pathlen of 0, do not sign more intermediate CAs
|
||||
return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
|
||||
}
|
||||
}
|
||||
|
||||
OverrideHosts(&safeTemplate, req.Hosts)
|
||||
safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject)
|
||||
|
||||
|
|
@ -331,7 +352,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
|
|||
|
||||
for _, server := range profile.CTLogServers {
|
||||
log.Infof("submitting poisoned precertificate to %s", server)
|
||||
var ctclient = client.New(server)
|
||||
var ctclient = client.New(server, nil)
|
||||
var resp *ct.SignedCertificateTimestamp
|
||||
resp, err = ctclient.AddPreChain(prechain)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -53,13 +53,14 @@ type Extension struct {
|
|||
// Extensions requested in the CSR are ignored, except for those processed by
|
||||
// ParseCertificateRequest (mainly subjectAltName).
|
||||
type SignRequest struct {
|
||||
Hosts []string `json:"hosts"`
|
||||
Request string `json:"certificate_request"`
|
||||
Subject *Subject `json:"subject,omitempty"`
|
||||
Profile string `json:"profile"`
|
||||
Label string `json:"label"`
|
||||
Serial *big.Int `json:"serial,omitempty"`
|
||||
Extensions []Extension `json:"extensions,omitempty"`
|
||||
Hosts []string `json:"hosts"`
|
||||
Request string `json:"certificate_request"`
|
||||
Subject *Subject `json:"subject,omitempty"`
|
||||
Profile string `json:"profile"`
|
||||
CRLOverride string `json:"crl_override"`
|
||||
Label string `json:"label"`
|
||||
Serial *big.Int `json:"serial,omitempty"`
|
||||
Extensions []Extension `json:"extensions,omitempty"`
|
||||
}
|
||||
|
||||
// appendIf appends to a if s is not an empty string.
|
||||
|
|
@ -160,26 +161,46 @@ func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
|
|||
// ParseCertificateRequest takes an incoming certificate request and
|
||||
// builds a certificate template from it.
|
||||
func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
|
||||
csr, err := x509.ParseCertificateRequest(csrBytes)
|
||||
csrv, err := x509.ParseCertificateRequest(csrBytes)
|
||||
if err != nil {
|
||||
err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
|
||||
err = helpers.CheckSignature(csrv, csrv.SignatureAlgorithm, csrv.RawTBSCertificateRequest, csrv.Signature)
|
||||
if err != nil {
|
||||
err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
|
||||
return
|
||||
}
|
||||
|
||||
template = &x509.Certificate{
|
||||
Subject: csr.Subject,
|
||||
PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
|
||||
PublicKey: csr.PublicKey,
|
||||
Subject: csrv.Subject,
|
||||
PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
|
||||
PublicKey: csrv.PublicKey,
|
||||
SignatureAlgorithm: s.SigAlgo(),
|
||||
DNSNames: csr.DNSNames,
|
||||
IPAddresses: csr.IPAddresses,
|
||||
EmailAddresses: csr.EmailAddresses,
|
||||
DNSNames: csrv.DNSNames,
|
||||
IPAddresses: csrv.IPAddresses,
|
||||
EmailAddresses: csrv.EmailAddresses,
|
||||
}
|
||||
|
||||
for _, val := range csrv.Extensions {
|
||||
// Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9)
|
||||
// extension and append to template if necessary
|
||||
if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
|
||||
var constraints csr.BasicConstraints
|
||||
var rest []byte
|
||||
|
||||
if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil {
|
||||
return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
|
||||
} else if len(rest) != 0 {
|
||||
return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints"))
|
||||
}
|
||||
|
||||
template.BasicConstraintsValid = true
|
||||
template.IsCA = constraints.IsCA
|
||||
template.MaxPathLen = constraints.MaxPathLen
|
||||
template.MaxPathLenZero = template.MaxPathLen == 0
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
|||
0
vendor/github.com/google/certificate-transparency/go/asn1/asn1.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/asn1/asn1.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/asn1/common.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/asn1/common.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/asn1/marshal.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/asn1/marshal.go
generated
vendored
Normal file → Executable file
|
|
@ -17,7 +17,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/certificate-transparency/go"
|
||||
"github.com/mreiferson/go-httpclient"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
@ -25,6 +24,7 @@ import (
|
|||
const (
|
||||
AddChainPath = "/ct/v1/add-chain"
|
||||
AddPreChainPath = "/ct/v1/add-pre-chain"
|
||||
AddJSONPath = "/ct/v1/add-json"
|
||||
GetSTHPath = "/ct/v1/get-sth"
|
||||
GetEntriesPath = "/ct/v1/get-entries"
|
||||
)
|
||||
|
|
@ -57,6 +57,12 @@ type addChainResponse struct {
|
|||
Signature string `json:"signature"` // Log signature for this SCT
|
||||
}
|
||||
|
||||
// addJSONRequest represents the JSON request body sent ot the add-json CT
|
||||
// method.
|
||||
type addJSONRequest struct {
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// getSTHResponse respresents the JSON response to the get-sth CT method
|
||||
type getSTHResponse struct {
|
||||
TreeSize uint64 `json:"tree_size"` // Number of certs in the current tree
|
||||
|
|
@ -102,18 +108,12 @@ type getEntryAndProofResponse struct {
|
|||
// New constructs a new LogClient instance.
|
||||
// |uri| is the base URI of the CT log instance to interact with, e.g.
|
||||
// http://ct.googleapis.com/pilot
|
||||
func New(uri string) *LogClient {
|
||||
var c LogClient
|
||||
c.uri = uri
|
||||
transport := &httpclient.Transport{
|
||||
ConnectTimeout: 10 * time.Second,
|
||||
RequestTimeout: 30 * time.Second,
|
||||
ResponseHeaderTimeout: 30 * time.Second,
|
||||
MaxIdleConnsPerHost: 10,
|
||||
DisableKeepAlives: false,
|
||||
// |hc| is the underlying client to be used for HTTP requests to the CT log.
|
||||
func New(uri string, hc *http.Client) *LogClient {
|
||||
if hc == nil {
|
||||
hc = new(http.Client)
|
||||
}
|
||||
c.httpClient = &http.Client{Transport: transport}
|
||||
return &c
|
||||
return &LogClient{uri: uri, httpClient: hc}
|
||||
}
|
||||
|
||||
// Makes a HTTP call to |uri|, and attempts to parse the response as a JSON
|
||||
|
|
@ -154,7 +154,6 @@ func (c *LogClient) postAndParse(uri string, req interface{}, res interface{}) (
|
|||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
httpReq.Header.Set("Keep-Alive", "timeout=15, max=100")
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
resp, err := c.httpClient.Do(httpReq)
|
||||
// Read all of the body, if there is one, so that the http.Client can do
|
||||
|
|
@ -277,6 +276,37 @@ func (c *LogClient) AddChainWithContext(ctx context.Context, chain []ct.ASN1Cert
|
|||
return c.addChainWithRetry(ctx, AddChainPath, chain)
|
||||
}
|
||||
|
||||
func (c *LogClient) AddJSON(data interface{}) (*ct.SignedCertificateTimestamp, error) {
|
||||
req := addJSONRequest{
|
||||
Data: data,
|
||||
}
|
||||
var resp addChainResponse
|
||||
_, _, err := c.postAndParse(c.uri+AddJSONPath, &req, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawLogID, err := base64.StdEncoding.DecodeString(resp.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawSignature, err := base64.StdEncoding.DecodeString(resp.Signature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds, err := ct.UnmarshalDigitallySigned(bytes.NewReader(rawSignature))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var logID ct.SHA256Hash
|
||||
copy(logID[:], rawLogID)
|
||||
return &ct.SignedCertificateTimestamp{
|
||||
SCTVersion: resp.SCTVersion,
|
||||
LogID: logID,
|
||||
Timestamp: resp.Timestamp,
|
||||
Extensions: ct.CTExtensions(resp.Extensions),
|
||||
Signature: *ds}, nil
|
||||
}
|
||||
|
||||
// GetSTH retrieves the current STH from the log.
|
||||
// Returns a populated SignedTreeHead, or a non-nil error.
|
||||
func (c *LogClient) GetSTH() (sth *ct.SignedTreeHead, err error) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"container/list"
|
||||
"crypto"
|
||||
"encoding/asn1"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -23,6 +24,8 @@ const (
|
|||
const (
|
||||
MaxCertificateLength = (1 << 24) - 1
|
||||
MaxExtensionsLength = (1 << 16) - 1
|
||||
MaxSCTInListLength = (1 << 16) - 1
|
||||
MaxSCTListLength = (1 << 16) - 1
|
||||
)
|
||||
|
||||
func writeUint(w io.Writer, value uint64, numBytes int) error {
|
||||
|
|
@ -80,13 +83,12 @@ func readVarBytes(r io.Reader, numLenBytes int) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
data := make([]byte, l)
|
||||
n, err := r.Read(data)
|
||||
if err != nil {
|
||||
if n, err := io.ReadFull(r, data); err != nil {
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if n != int(l) {
|
||||
return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
|
|
@ -510,3 +512,52 @@ func SerializeSTHSignatureInput(sth SignedTreeHead) ([]byte, error) {
|
|||
return nil, fmt.Errorf("unsupported STH version %d", sth.Version)
|
||||
}
|
||||
}
|
||||
|
||||
// SCTListSerializedLength determines the length of the required buffer should a SCT List need to be serialized
|
||||
func SCTListSerializedLength(scts []SignedCertificateTimestamp) (int, error) {
|
||||
if len(scts) == 0 {
|
||||
return 0, fmt.Errorf("SCT List empty")
|
||||
}
|
||||
|
||||
sctListLen := 0
|
||||
for i, sct := range scts {
|
||||
n, err := sct.SerializedLength()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to determine length of SCT in position %d: %v", i, err)
|
||||
}
|
||||
if n > MaxSCTInListLength {
|
||||
return 0, fmt.Errorf("SCT in position %d too large: %d", i, n)
|
||||
}
|
||||
sctListLen += 2 + n
|
||||
}
|
||||
|
||||
return sctListLen, nil
|
||||
}
|
||||
|
||||
// SerializeSCTList serializes the passed-in slice of SignedCertificateTimestamp into a
|
||||
// byte slice as a SignedCertificateTimestampList (see RFC6962 Section 3.3)
|
||||
func SerializeSCTList(scts []SignedCertificateTimestamp) ([]byte, error) {
|
||||
size, err := SCTListSerializedLength(scts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fullSize := 2 + size // 2 bytes for length + size of SCT list
|
||||
if fullSize > MaxSCTListLength {
|
||||
return nil, fmt.Errorf("SCT List too large to serialize: %d", fullSize)
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Grow(fullSize)
|
||||
if err = writeUint(buf, uint64(size), 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, sct := range scts {
|
||||
serialized, err := SerializeSCT(sct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = writeVarBytes(buf, serialized, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return asn1.Marshal(buf.Bytes()) // transform to Octet String
|
||||
}
|
||||
|
|
|
|||
0
vendor/github.com/google/certificate-transparency/go/x509/cert_pool.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/cert_pool.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pem_decrypt.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pem_decrypt.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pkcs1.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pkcs1.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pkcs8.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pkcs8.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pkix/pkix.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/pkix/pkix.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_darwin.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_darwin.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_plan9.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_plan9.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_stub.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_stub.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_unix.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_unix.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_windows.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/root_windows.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/sec1.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/sec1.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/verify.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/verify.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/x509.go
generated
vendored
Normal file → Executable file
0
vendor/github.com/google/certificate-transparency/go/x509/x509.go
generated
vendored
Normal file → Executable file
Loading…
Reference in New Issue