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:
Roland Bracewell Shoemaker 2016-07-12 13:59:50 -07:00 committed by Jacob Hoffman-Andrews
parent 8cd74bf766
commit 887618effc
28 changed files with 349 additions and 111 deletions

52
Godeps/Godeps.json generated
View File

@ -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",

View File

@ -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 {

View File

@ -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"}

View File

@ -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 {

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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
View File

0
vendor/github.com/google/certificate-transparency/go/asn1/common.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/asn1/marshal.go generated vendored Normal file → Executable file
View File

View 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) {

View File

@ -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
View File

0
vendor/github.com/google/certificate-transparency/go/x509/pem_decrypt.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/pkcs1.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/pkcs8.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/pkix/pkix.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/root.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/root_darwin.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/root_plan9.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/root_stub.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/root_unix.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/root_windows.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/sec1.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/verify.go generated vendored Normal file → Executable file
View File

0
vendor/github.com/google/certificate-transparency/go/x509/x509.go generated vendored Normal file → Executable file
View File